XAML - How to have global inputBindings?

11,014

One solution is to use an Attached Property with a Style to set the InputBindings on all the controls of a given type in your application. Unfortunately, since you can't make a "catch-all" Style (that I know of, anyway), you'll have to create a Style for each control type on which you want to set the InputBindings (this shouldn't, however, be too many controls). Below is some sample code that shows how to do this:

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

namespace WpfApplication1
{
    public class MyAttached
    {
        public static readonly DependencyProperty InputBindingsProperty =
            DependencyProperty.RegisterAttached("InputBindings", typeof(InputBindingCollection), typeof(MyAttached),
            new FrameworkPropertyMetadata(new InputBindingCollection(),
            (sender, e) =>
            {
                var element = sender as UIElement;
                if (element == null) return;
                element.InputBindings.Clear();
                element.InputBindings.AddRange((InputBindingCollection)e.NewValue);
            }));

        public static InputBindingCollection GetInputBindings(UIElement element)
        {
            return (InputBindingCollection)element.GetValue(InputBindingsProperty);
        }

        public static void SetInputBindings(UIElement element, InputBindingCollection inputBindings)
        {
            element.SetValue(InputBindingsProperty, inputBindings);
        }

    }
}

<Application x:Class="WpfApplication1.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:loc="clr-namespace:WpfApplication1"
    StartupUri="Window1.xaml">
    <Application.Resources>
        <Style TargetType="TextBox">
            <Setter Property="loc:MyAttached.InputBindings">
                <Setter.Value>
                    <InputBindingCollection>
                        <KeyBinding Key="A" Modifiers="Ctrl" Command="loc:Window1.MyAction" />
                    </InputBindingCollection>
                </Setter.Value>
            </Setter>
        </Style>
        <Style TargetType="Button">
            <Setter Property="loc:MyAttached.InputBindings">
                <Setter.Value>
                    <InputBindingCollection>
                        <KeyBinding Key="A" Modifiers="Ctrl" Command="loc:Window1.MyAction" />
                    </InputBindingCollection>
                </Setter.Value>
            </Setter>
        </Style>
    </Application.Resources>
</Application>

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:loc="clr-namespace:WpfApplication1"
    Title="Window1" Height="300" Width="300">
    <Window.CommandBindings>
        <CommandBinding Command="loc:Window1.MyAction" Executed="MyAction_Executed" />
    </Window.CommandBindings>
    <StackPanel>
        <Button Content="Try Ctrl+A Here!" />
        <TextBox Text="Try Ctrl+A Here!" />
    </StackPanel>
</Window>

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

namespace WpfApplication1
{
    public partial class Window1
    {
        public static readonly RoutedUICommand MyAction = new RoutedUICommand("MyAction", "MyAction", typeof(Window1));

        public Window1() { InitializeComponent(); }

        private void MyAction_Executed(object sender, ExecutedRoutedEventArgs e) { MessageBox.Show("MyAction!"); }
    }
}
Share:
11,014
rockeye
Author by

rockeye

Learning is a great source of happiness

Updated on June 06, 2022

Comments

  • rockeye
    rockeye about 2 years

    I have a WPF application with several windows. I would like to define GLOBAL inputBindings.

    To define LOCAL inputbindings, i just declare the input in Window.InputBindings or UserControl.InputBindings.

    To define GLOBALs, I wish i could do the same with the Application class...

    <Application
    ....>
    <Application.InputBindings>
    ...
    </Application.InputBindings>
    

    If i have the same binding in 2 different windows, i have to code it twice. This doesn't meet D.R.Y.'s philosophy and i guess there is a better way...

    EDIT : in his answer Kent Boogaart advices me to use Style. Unfortunately, i can't figure out how to define it. This is the code :

     <Application.Resources>
        <Style TargetType="Window">
            <Setter Property="InputBindings">
                <Setter.Value>
                    <Window.InputBindings>
                        <KeyBinding KeyGesture="Ctrl+M" Command="local:App.MsgCommand />
                    </Window.InputBindings>
                </Setter.Value>
            </Setter>
        </Style>
    </Application.Resources> 
    

    It raises an error : error MC3080: The Property Setter 'InputBindings' cannot be set because it does not have an accessible set accessor.

    Is my style wrong? Is there another solution?

    Any ideas? thanks!

  • Asheh
    Asheh over 9 years
    Beware - I had some very weird problems when using the above code. It worked great until I applied it to a style, then in random cases it would appear to work but then the DataContext would be null (thus none of the commands would bind). I could not figure out why this would happen randomly.