将命令绑定到代码隐藏中的键绑定

时间:2016-10-12 07:58:39

标签: c# wpf xaml mvvm data-binding

我想在我的应用程序中添加一些通用键盘快捷键。目前,在每个View XAML中我都添加了以下代码:

500 HTML::Parser object version 3.35 does not match bootstrap parameter 3.72

为了概括这一点,我想继承WPF Window类并使用新创建的子类。现在我想知道如何在相应的代码中绑定这些键盘命令。目前它看起来像这样:

<Window.InputBindings>
    <KeyBinding Command="{Binding ZoomInCommand}" Key="Add" Modifiers="Control" />
    <KeyBinding Command="{Binding ZoomOutCommand}" Key="Subtract" Modifiers="Control" />
</Window.InputBindings>

但这对我来说并不合适,因为我需要直接访问DataContext并转换它而不是使用Binding()对象。如何更改代码以使其看起来更像MVVM?

2 个答案:

答案 0 :(得分:1)

您需要的是依赖属性

MyWindow中,为两个命令创建ICommand依赖项属性,您还需要实现回调方法依赖项属性值发生变化,这里是ZoomInCommand的一个:

public ICommand ZoomInCommand
{
    get { return (ICommand)GetValue(ZoomInCommandProperty); }
    set { SetValue(ZoomInCommandProperty, value); }
}

// Using a DependencyProperty as the backing store for ZoomInCommand.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty ZoomInCommandProperty =
    DependencyProperty.Register("ZoomInCommand", typeof(ICommand), typeof(MyWindow), new PropertyMetadata(null, new PropertyChangedCallback(OnZoomInCommandChanged)));

...

private static void OnZoomInCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    MyWindow wnd = (MyWindow)d;

    //Remove the old key binding if there is one.
    wnd.RemoveInputBinding(e.OldValue as ICommand);

    //Add the new input binding.
    if (e.NewValue != null)
        wnd.InputBindings.Add(new KeyBinding((ICommand)e.NewValue, Key.Add, ModifierKeys.Control));
}

private void RemoveInputBinding(ICommand command)
{
    if (command == null)
        return;

    //Find the old binding if there is one.
    InputBinding oldBinding = null;

    foreach (InputBinding binding in InputBindings)
    {
        if (binding.Command == command)
        {
            oldBinding = binding;
            break;
        }
    }

    //Remove the old input binding.
    if (oldBinding != null)
        InputBindings.Remove(oldBinding);
}

那么上面的代码到底是做什么的呢?

在依赖项属性上,可以选择使用PropertyChangedCallback方法,只要属性值发生变化就会触发,这很好,因为我们可以使用它来删除旧的{{如果要更改值,请创建一个新的InputBinding。在您的情况下,只要InputBinding发生更改,该值就会发生变化。

每当属性值发生变化时,步骤都非常简单:

  1. 删除旧DataContext的旧InputCommand
  2. 为新ICommand添加新的InputCommand
  3. 我创建了一个方便的ICommand方法,这样可以更容易地为您的其他依赖项属性重用代码,这取决于您实现。

    要将这一切放在一起,在RemoveInputBinding事件处理程序中,您只需编写手动绑定:

    DataContextChanged

    这将确保您不再需要担心将private void MyWindow_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { //Bind this.ZoomInCommand to DataContext.ZoomInCommand Binding zoomInCommandBinding = new Binding("ZoomInCommand"); zoomInCommandBinding.Source = DataContext; this.SetBinding(MyWindow.ZoomInCommandProperty, zoomInCommandBinding); ... } 转换为DataContext,只需尝试绑定到IZoomableViewModel。如果ZoomInCommand中没有这样的命令,那么它将无声地失败。如果它确实成功,则会触发DataContext并为该命令创建PropertyChangedCallback

答案 1 :(得分:1)

我发现了一个很好用的简单解决方案,似乎模仿了XAML解析器的行为。基本上,对于放大功能,我将以下代码放在MyWindow构造函数中:

var zoomInKeyBinding = new KeyBinding { Key = Key.Add, Modifiers = ModifierKeys.Control };
BindingOperations.SetBinding(
    zoomInKeyBinding,
    InputBinding.CommandProperty,
    new Binding { Path = new PropertyPath("ZoomInCommand") }
);
InputBindings.Add(zoomInKeyBinding);

当然绑定的ViewModel需要适当地实现ZoomInCommand。