2011-09-22 34 views
1

我正在開發一個MVVM應用程序。我有一個主窗口,它看起來或多或少是這樣的:MVVM應用程序中的子視圖焦點查看命令

<Window> 
    <ContentControl Content={Binding ContentViewModel} /> 
</Window> 

然後,我有這個視圖模型,它暴露了一定的數量的命令,我想這些命令都可獲得從UI用戶(帶按鈕等)和鍵盤上的鍵,使用KeyBindings。

這些命令可以從UI按鈕中正常使用。但是Keybindings並不總是能夠工作,但在我看來,問題在於加載的視圖並不總是處於焦點。 這是視圖的代碼。

<UserControl> 
    <UserControl.InputBindings> 
     <KeyBinding Key="Delete" Command="{Binding RemoveEntityCommand, ElementName=Designer}" /> 
    </UserControl.InputBindings> 
    <Grid> 
     <namespace:Designer x:Name="Designer" /> 
    </Grid> 
</UserControl> 

如何解決這個永久的MVVM應用程序?我多次遇到此問題。

注意:爲簡單起見,刪除了所有名稱空間聲明。

謝謝。

回答

2

我可能會附加一個命令到Window而不是UserControl的KeyDown或KeyUp事件,並從那裏路由它。

它可以被路由到ShellViewModel,如果需要,它可以將它傳遞給當前ContentViewModel,或者可能使用某種廣播特殊組合鍵的消息系統,ViewModel可以訂閱它們。

+0

那麼沒有辦法從XAML獲得重點? –

+0

我不認爲你可以一次設置多個對象的焦點,除非他們在不同的焦點範圍。當你看到只有你的'UserControl'時,你是否想要限制焦點? – Rachel

1

我會怎麼做,是實現PreviewKeyUp事件,並用它來調用一個方法在我的視圖模型,這樣的事情:

protected void PreviewKeyUp(object sender, KeyEventArgs args) 
{ 
    args.Handled = myViewModel.HandleKeyUp(args.Key); 
} 

public bool HandleKeyUp(Key key) 
{ 
    // Determine if you should execute a command 
    if(myCommands.ShouldExecuteOnKey(key)) 
    { 
     // Execute the commad 
     return true; 
    } 

    return false; 
} 

很多人似乎認爲,MVVM意味着沒有代碼 - 在後面,但這並非總是如此,甚至不可能。

+0

我很舒服,使用後面的代碼,只要它是唯一的辦法,我更喜歡使用的元素,他們的目的的方式,我也可以用邏輯上的自定義代碼取代Commands,但是有一種更舒適的方式,所以我堅持這一點。謝謝。 –

0

是的,鍵綁定是一種痛苦。我同意瑞秋的看法,你可能希望在這個具體案例的窗口層面提供一些可用的東西。

可以避免後面的代碼,並通過執行以下操作獲得MVVM的善良:

  1. 讓你的命令,瞭解重要的手勢
  2. 的給一個鍵綁定的附加屬性,它充分利用了(1 )

這顯然是一個基礎架構工作,它是可測試和可重用的,一旦你有它的位置。在這種情況下,由於您希望綁定在窗口級別可用,因此您的ShellVm會根據需要保存命令和委託給子視圖模型。我已經離開下方足夠的代碼給你的感覺的想法

HTH,
Berryl

樣本綁定

<Window.InputBindings> 
    <cmdRef:KeyBindingEx CommandReference="{Binding AddCommand}"/> 
</Window.InputBindings> 

擴展鍵聯結

public class KeyBindingEx : KeyBinding 
{ 
    public static readonly DependencyProperty CommandReferenceProperty = DependencyProperty 
     .Register("CommandReference", typeof(CommandReference), typeof(KeyBindingEx),   
        new PropertyMetadata(OnCommandReferenceChanged)); 

    private static void OnCommandReferenceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { 
     var kb = (KeyBinding) d; 
     var cmdRef = e.NewValue as VmCommand; 
     if(cmdRef==null) return; 

     kb.Key = cmdRef.GestureKey; 
     kb.Modifiers = cmdRef.GestureModifier; 
     kb.Command = cmdRef; 
    } 

    public CommandReference CommandReference 
    { 
     get { return (CommandReference)GetValue(CommandReferenceProperty); } 
     set { SetValue(CommandReferenceProperty, value); } 
    } 
} 

命令參考基地類提取物

公共類CommandReference:PropertyChangedBase { ...

public Key GestureKey 
    { 
     get { return _gestureKey; } 
     set 
     { 
      if (_gestureKey == value) return; 

      _gestureKey = value; 
      NotifyOfPropertyChange(() => GestureKey); 
     } 
    } 
    private Key _gestureKey;   
} 

/// <summary>A command whose primary purpose is to relay its functionality to other objects by invoking delegates.</summary> 
public class VmCommand : CommandReference, ICommand 
{ 
    ... 

    /// <summary>Action to be called when the Execute method of the command gets called</summary> 
    public Action ExecuteDelegate { get; protected set; } 

    /// <summary>Predicate to execute when the CanExecute of the command gets called (default is <c>true</c>)</summary> 
    public Func<bool> CanExecuteDelegate { get; protected set; } 

}