Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF: How to prevent a control from stealing a key gesture?

In my WPF application I would like to attach an input gesture to a command so that the input gesture is globally available in the main window, no matter which control has the focus.

In my case I would like to bind Key.PageDown to a command, however, as soon as certain controls receive the focus (e.g. a TextBox or TreeView control), these controls receive the key events and the command is no longer triggered. These controls have no specific CommandBindings or InputBindings defined.

This is how I define my input gesture:

XAML:

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" >
    <StackPanel>
        <TreeView>
            <TreeViewItem Header="1">
                <TreeViewItem Header="1.1"></TreeViewItem>
                <TreeViewItem Header="1.2"></TreeViewItem>
            </TreeViewItem>
            <TreeViewItem Header="2" ></TreeViewItem>
        </TreeView>
        <TextBox />
        <Label Name="label1" />
    </StackPanel>
</Window>

Code:

using System;
using System.Windows;
using System.Windows.Input;

public static class Commands
{
    private static RoutedUICommand _myCommand;

    static Commands()
    {
        _myCommand = new RoutedUICommand("My Command",
            "My Command",
            typeof(Commands),
            new InputGestureCollection()
                {
                    new KeyGesture(Key.PageDown, ModifierKeys.None)
                });
    }

    public static ICommand MyCommand
    {
        get { return _myCommand; }
    }
}

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();

        CommandBinding cb = new CommandBinding();
        cb.Command = Commands.MyCommand;
        cb.Executed += new ExecutedRoutedEventHandler(cb_Executed);
        cb.CanExecute += new CanExecuteRoutedEventHandler(cb_CanExecute);
        this.CommandBindings.Add(cb);
    }

    void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;
    }

    void cb_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        this.label1.Content = string.Format("My Command was executed {0}", DateTime.Now);
    }
}

I already tried catching the window's PreviewKeyDown event and marking it as handled This had not the desired effect. I also set the Focusable property to false. This helped for TextBox controls, but not for the TreeView (and has the unwanted effect, that the TextBox no longer can be edited so it is not a solution for me).

So my question is how can I define a keyboard shortcut that works everywhere in the main window?

like image 300
Dirk Vollmar Avatar asked Dec 14 '09 11:12

Dirk Vollmar


1 Answers

The following workaround seems to have the desired effect of having the command global to the window; however, I still wonder whether there is no easier way to do this in WPF:

private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
    foreach (InputBinding inputBinding in this.InputBindings)
    {
        KeyGesture keyGesture = inputBinding.Gesture as KeyGesture;
        if (keyGesture != null && keyGesture.Key == e.Key && keyGesture.Modifiers == Keyboard.Modifiers)
        {
            if (inputBinding.Command != null)
            {
                inputBinding.Command.Execute(0);
                e.Handled = true;
            }
        }
    }

    foreach (CommandBinding cb in this.CommandBindings)
    {
        RoutedCommand command = cb.Command as RoutedCommand;
        if (command != null)
        {
            foreach (InputGesture inputGesture in command.InputGestures)
            {
                KeyGesture keyGesture = inputGesture as KeyGesture;
                if (keyGesture != null && keyGesture.Key == e.Key && keyGesture.Modifiers == Keyboard.Modifiers)
                {
                    command.Execute(0, this);
                    e.Handled = true;
                }
            }
        }
    }
}

}

like image 132
Dirk Vollmar Avatar answered Oct 02 '22 09:10

Dirk Vollmar