XAML - 如何拥有全局的inputBindings?

7
我有一个包含多个窗口的WPF应用程序。我想定义全局输入绑定。
要定义本地输入绑定,我只需在Window.InputBindings或UserControl.InputBindings中声明输入即可。
为了定义全局输入绑定,我希望能够使用Application类执行相同的操作...
<Application
....>
<Application.InputBindings>
...
</Application.InputBindings>

如果我在两个不同的窗口中有相同的绑定,我必须编写两次代码。这不符合D.R.Y.的理念,我想肯定有更好的方法...
编辑:在他的回答中Kent Boogaart建议我使用Style。不幸的是,我无法弄清楚如何定义它。这是代码:
 <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> 

它引发了一个错误: 错误MC3080:属性设置器'InputBindings'无法设置,因为它没有可访问的设置访问器。

我的样式有问题吗? 还有其他解决方案吗?

有任何想法吗?谢谢!

2个回答

10

一个解决方案是使用附加属性样式一起,设置给定类型控件中所有控件的InputBindings。不幸的是,由于我所知道的没有"catch-all"的Style,因此你需要为每个要设置InputBindings的控件类型创建一个Style(但这不应该是太多的控件)。下面是一些示例代码,演示了如何做到这一点:

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!"); }
    }
}

注意 - 当我使用上述代码时,遇到了一些非常奇怪的问题。它在应用到样式之前运行得很好,但在某些情况下,它似乎可以工作,但是 DataContext 会变成 null(因此没有任何命令会绑定)。我无法弄清楚为什么会随机发生这种情况。 - Asheh

-1
你可以创建一个应用于所有窗口的“样式(Style)”。该“样式”可以设置“输入绑定(InputBindings)”。

很不幸,由于InputBindings不是依赖属性,所以这种方法行不通。 - StayOnTarget

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接