如何简化XAML中的InputBindings?

时间:2014-07-04 18:03:26

标签: c# wpf xaml mvvm inputbinding

首先,这是我的代码:

<Window ...>
<Window.Resources>

</Window.Resources>
<Window.InputBindings>
    <KeyBinding Key="Space" Command="{Binding KeyboardCommand}" CommandParameter="Space"/>
    <KeyBinding Key="OemPeriod" Command="{Binding KeyboardCommand}" CommandParameter="Blank"/>
    <KeyBinding Key="D0" Command="{Binding KeyboardCommand}" CommandParameter="Rest"/>
    <KeyBinding Key="D1" Command="{Binding KeyboardCommand}" CommandParameter="N1"/>
    <KeyBinding Key="D2" Command="{Binding KeyboardCommand}" CommandParameter="N2"/>
    <KeyBinding Key="D3" Command="{Binding KeyboardCommand}" CommandParameter="N3"/>
    <KeyBinding Key="D4" Command="{Binding KeyboardCommand}" CommandParameter="N4"/>
    <KeyBinding Key="D5" Command="{Binding KeyboardCommand}" CommandParameter="N5"/>
    <KeyBinding Key="D6" Command="{Binding KeyboardCommand}" CommandParameter="N6"/>
    <KeyBinding Key="D7" Command="{Binding KeyboardCommand}" CommandParameter="N7"/>

    <KeyBinding Modifiers="Control" Key="Space" Command="{Binding KeyboardCommand}" CommandParameter="Space"/>
    <KeyBinding Modifiers="Control" Key="OemPeriod" Command="{Binding KeyboardCommand}" CommandParameter="Blank"/>
    <KeyBinding Modifiers="Control" Key="D0" Command="{Binding KeyboardCommand}" CommandParameter="Rest"/>
    <KeyBinding Modifiers="Control" Key="D1" Command="{Binding KeyboardCommand}" CommandParameter="N1"/>
    <KeyBinding Modifiers="Control" Key="D2" Command="{Binding KeyboardCommand}" CommandParameter="N2"/>
    <KeyBinding Modifiers="Control" Key="D3" Command="{Binding KeyboardCommand}" CommandParameter="N3"/>
    <KeyBinding Modifiers="Control" Key="D4" Command="{Binding KeyboardCommand}" CommandParameter="N4"/>
    <KeyBinding Modifiers="Control" Key="D5" Command="{Binding KeyboardCommand}" CommandParameter="N5"/>
    <KeyBinding Modifiers="Control" Key="D6" Command="{Binding KeyboardCommand}" CommandParameter="N6"/>
    <KeyBinding Modifiers="Control" Key="D7" Command="{Binding KeyboardCommand}" CommandParameter="N7"/>

    ...
</Window.InputBindings>
<Grid>
    ...
</Grid>

这些代码没有错误,所以它可以正常工作。但是,如果我的应用程序有很多InputBindings,似乎InputBindings 可以获得很多行。

那么,是否有可能简化 /缩短它们(以任何方式)?这是因为我的应用程序需要很多 InputBindings / KeyBinding修饰符组合,并且感觉它是逐个输入的会看起来“不整洁”。中号

或许它是唯一的方法(使用MVVM)?

请澄清所需的一切:D


如果需要,这些是Command和ViewModel类中的相关方法:

public void Execute(object parameter)
{
    Notes note;
    if (Enum.TryParse(parameter.ToString(), out note))
    {
        _vm.AddOrUpdateNote(note, Keyboard.Modifiers);
    }
    else
    {
        ...
    }
}

我的ViewModel的一部分:

public void AddOrUpdateNote(Notes note, ModifierKeys mKeys)
{
    if (mKeys == ModifierKeys.Control)
    {
        ...
    }
    else if (mKeys == ModifierKeys.Shift)
    {
        ...
    }
    else
    {
        ...
    }
}

因此,根据按下哪个修改键,存在轻微的行为差异。 (分裂成不同的方法对我来说很糟糕)


更新: 我已经阅读了InputGestures的一些解释。在http://msdn.microsoft.com/en-us/library/ms752308%28v=vs.110%29.aspx中,它是this.InputBindings.Add(Blabla)(我猜是来自xaml.cs),可以在ViewModel中完成吗?或者它是否需要通过XAML完成,因此,如果我的应用程序中有很多组合键,例如上面的示例,它仍然需要以“长”的方式完成?< / p>

请尽可能提供一些代码示例,以便我能更好地理解它。感谢

(不太确定如何提问,所以请随时澄清)

2 个答案:

答案 0 :(得分:1)

如果您的唯一目标是减少手动KeyBindings的数量,您可以这样做:

var keys = new List<Key> { Key.Space, Key.OemPeriod, Key.D1, [...]};
foreach(var key in keys)
{
     this.InputBindings.Add(new KeyBinding() { Command = MyCommandClass.KeyboardCommand, CommandParameter = key});
]

但是我不喜欢这种方法,因为它要求你自己实现命令的委托,而不是让WPF这样做。您需要打开CommandParameter和modifierkey。

以上内容绝对有效,但只需一个命令就可以完成所有工作,这对我来说是违反直觉的。我将实现几个命令(如AddNoteCommand),以便它们各自拥有自己的Execute和CanExecute方法。

是的,每个Command都有一些额外的代码行,但是你的命令实现不必知道你是如何访问命令的。想象一下,您想要在UI中将这些命令添加为MenuItems或Buttons。

可能有些东西我不知道(我不知道这些命令是做什么的),但我无法想象我会选择这种方法的场景。

但这并不一定会使它错误;)

答案 1 :(得分:0)

实际上,您可以围绕附加属性使用一个技巧。应用附加属性的语法实际上只是从 XAML 调用特定类上的静态函数的“语法糖”。知道这一点后,您就可以构建一个“Utility”类,该类具有许多可以使用附加属性语法从 XAML 调用的方法。

因此,你可以做这样的事情......

public namespace My{

    public static class Util {

        [AttachedPropertyBrowsableForType(typeof(KeyBinding))]
        public static void SetSet(KeyBinding keyBinding, string bindingData){

            // Add code here to parse the string and do with it what you will.
            // For instance, you can split it on a pipe character to get the modifier,
            // parameter and key, then just apply it to the passed-in keyBinding here.
            // I'll leave this part as an exercise for you to research.
        }
    }
}

你可以这样使用它...

<Window ...>
    <Window.InputBindings>
        <KeyBinding my:Util.Set="Control|D1|N1" />
        <KeyBinding my:Util.Set="Control|D2|N2" />
        <KeyBinding my:Util.Set="Control|D3|N3" />

        ...

    </Window.InputBindings>
</Window>

注意事项:

  • 支持附加属性的方法名称是“拥有”类上名为 Set[PropertyName] 的静态方法。在 XAML 中使用它时,它看起来像 OwningClass.PropertyName="bla"。在我的示例中,通过调用类 Util 和静态方法 SetSet,“属性名称”变为 Set,因此在 XAML 中(其中“my”是导入的 xmlns 值),它看起来像 my:Util.Set="bla",它更清楚地表达了我的意图。

  • 我更喜欢数据类型 string,这样你就可以在一个值中传递大量信息,然后按照你认为合适的方式解析它。但是您可以使用任何您想要的数据类型。例如,您可以使用一个 CommandInfo 类来公开您的 ModifiersKeyParameter 属性,然后创建一个 MarkupExtension 来“创建”该类并它将它们作为构造函数参数,然后通过附加的属性语法设置它,如下所示:

<InputBinding my:Util.Set="{my:CommandInfo Control, D1, N1}" ... />

事实证明,这种附加属性语法在简化 XAML 方面非常出色。例如,我使用这些技术来更轻松地配置我的网格布局。例如,而不是这个...

<Grid>

    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>

    <TextBlock Grid.Row="1" Grid.Column="1", Grid.ColumnSpan="2" />

</Grid>

我现在可以这样做...

<Grid is:GridUtil.Layout="Auto,Auto,Auto|Auto,*">

    <TextBlock is:GridUtil.Cell="1,1s2" />

</Grid>

注意事项:

  • 布局是一个逗号分隔的行高列表、一个竖线字符,然后是一个逗号分隔的列宽列表
  • 单元格是一行(也可能是带有“sN”的行跨度)、一个逗号,然后是一列(也可能是带有“sN”的列跨度') 希望这会有所帮助!