2016-10-12 63 views
2

我想爲我的應用程序添加一些通用鍵盤快捷鍵。目前,在每一個視圖XAML我添加以下代碼:在代碼背後的綁定命令到KeyBinding

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

我爲了這個概括,我想繼承WPF窗口類,並使用新創建的子類來代替。現在我想知道如何在相應的代碼中綁定這些Keyboard命令。目前,它看起來像這樣:

public class MyWindow : Window 
{ 
    public MyWindow() 
    { 
     DataContextChanged += OnDataContextChanged; 
    } 

    private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) 
    { 
     InputBindings.Clear(); 
     var dataContext = DataContext as IZoomableViewModel; 
     if (dataContext != null) 
     { 
      InputBindings.Add(new KeyBinding(dataContext.ZoomInCommand, Key.Add, ModifierKeys.Control)); 
      InputBindings.Add(new KeyBinding(dataContext.ZoomOutCommand, Key.Subtract, ModifierKeys.Control)); 
     } 
    } 
} 

但這並不右看看我,因爲我需要直接訪問到DataContext並投它,而不是使用綁定()的對象。我如何更改代碼以使其看起來更像MVVM?

回答

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如果該值分別爲改變。在你的情況下,只要DataContext改變,該值就會改變。

因此,步驟很簡單,只要屬性值變化:

  1. ICommand卸下舊InputCommand
  2. ICommand添加新InputCommand

我已經創建了一個方便的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); 

    ... 
} 

這將確保您不再需要擔心鑄造DataContextIZoomableViewModel,您只需嘗試綁定到ZoomInCommand。如果在DataContext中沒有這樣的命令,那麼它將只是在默默地失敗。如果它確實成功,則將觸發PropertyChangedCallback,併爲該命令創建InputBinding

0

我發現了一個很好的簡單解決方案,似乎可以模仿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); 

當然綁定視圖模型需要適當地實施ZoomInCommand。

相關問題