2011-12-23 183 views
5

所有菜單/ contextmenus /工具欄在WPF我用在視圖模型代碼中聲明非常像這樣:「純」MVVM中的MenuItem鍵盤快捷鍵?

MenuService.Add(new MenuItem() 
    { 
    Header = "DoStuff", 
    Command = new relayCommand(DoStuff,() => CanDoStuffExecute()) 
    // some more properties like parent item/image/... 
    }); 

的MenuService提供了一個單一的結合點,這是菜單項的分級列表,並獲取綁定到實際的菜單的ItemsSource在xaml中。

這工作得很好,現在我想以相同的便捷方式添加鍵盤快捷鍵。 理想的菜單項會得到System.Windows.Input.KeyGesture類型的屬性,所以我可以簡單地寫

Shortcut = new KeyGesture(Key.D, ModifierKeys.Control) 

這將導致該項目的命令後擊中擁有菜單的窗口Ctrl + d被調用,而這也將導致菜單中自動顯示「Ctrl + D」。

但是我迷失在這裏:我想通過數據綁定來設置MenuItem.InputBindings集合,但它是隻能獲取的。無論如何,我怎樣才能將物品放入其中?還是有一個MVVM框架已經支持這樣的事情?我在鍵盤快捷鍵上找到的大多數q &都是關於通過xaml設置快捷方式的,這沒有任何幫助。

更新

搜索「relaycommand VS routeduicommand和‘relaycommand keygesture’等確實揭示了足夠的信息來與工作雖然哈克解決方案。在那裏肯定還有其他更好的方法,但目前這對我來說是非常低的優先事項,並且完美地完成了這項工作。我添加了兩個屬性,這樣MenuItem類:

//Upon setting a Gesture, the original command is replaced with a RoutedCommand 
//since that automatically gives us proper display of the keyboard shortcut. 
//The RoutedCommand simply calls back into the original Command. 
//It also sets the CommandBinding property, which still has to be added to the 
//CommandBindingCollection of either the bound control or one of it ancestors 
public InputGesture Gesture 
{ 
    set 
    { 
    var origCmd = Command; 
    if(origCmd == null) 
     return; 
    var routedCmd = new RoutedCommand(Header, 
     typeof(System.Windows.Controls.MenuItem), 
     new InputGestureCollection { value }); 
    CommandBinding = new CommandBinding(routedCmd, 
     (sender, args) => origCmd.Execute(args.Parameter), 
     (sender, args) => { args.CanExecute = origCmd.CanExecute(args.Parameter); }); 
    Command = routedCmd; 
    } 
} 

//CommandBinding created when setting Gesture 
public CommandBinding CommandBinding { get; private set; } 

所以這讓我問原來的功能(即添加在代碼中的鍵盤快捷鍵,他們是很容易配置等)。剩下的就是註冊命令綁定。目前,只需將它們全部添加到Application.Current.MainWindow.CommandBindings中即可完成。

回答

3

這實際上並不符合「答案」(我無法明確添加評論) - 但我建議您在做什麼,而不是WPF中的預期方法。您正在使用Windows Forms的方式(以及許多其他工具包) - 在代碼中定義UX。你儘可能地做到了,但現在你已經遇到了一堵磚牆:關鍵手勢純粹是UX,絕對不能在代碼隱藏中指定。外觀(作爲視圖模型的函數)以及用戶與它的交互(發出給定命令的方式)都是針對XAML定義的。

屬性值和命令用於您的視圖模型,以便您可以將此視圖模型用於其他視圖,還可以輕鬆地爲其創建單元測試。如何在視圖模型中實現鍵盤快捷鍵有助於可測試性?並且爲了在其他視圖中使用,可以爭辯說實際的快捷方式可能不適用於新的視圖,因此這不屬於這些視圖。當然你可能有其他的原因 - 但我建議你可以考慮在XAML中定義這些。

- 增加,響應你的comment-

你說得對 - 我已經看到了極力避免任何代碼和清盤不必要的鈍一些相當大的WPF UX項目。我試圖用任何一種方法產生一個工作結果,並且儘可能簡單。

這是一個簡單創建MenuItem的示例代碼片段。

<Menu x:Name="miMain" DockPanel.Dock="Top"> 
    <MenuItem Command="{Binding Path=MyGreatCommand}" Header="DoSomething"/> 

創建菜單。在這裏,MyGreatCommand是一個ICommand,它只是視圖模型的一個屬性。我一般把一個DockPanel內,處理StatusBar

要分配的關鍵姿勢..

<Window.InputBindings> 
    <KeyBinding Key="X" Modifiers="ALT" Command="{Binding Path=MyGreatCommand}"/> 

但是,既然你提到你已經尋找答案,發現只有XAML - 我假設你已經嘗試過這種方法。我已經使用RoutedUICommand而不是用戶定義的ICommand s,以在標題文本中獲得很好的右對齊的按鍵手勢,但是我還沒有找到如何做到這一點。如果你堅持用代碼創建命令和鍵盤手勢,你可能需要創建RoutedUICommand

爲什麼你想要在XAML以外設置按鍵手勢?

如果您希望在某些國家您的視圖模型中佔據主導地位的一些菜單項僅出現,那麼你就可以在菜單項的Visibility屬性(可以包含其他的菜單項)綁定到CollapsedVisible

+0

你能提供一些代碼示例嗎?你的意思是我應該在xaml中定義完整的菜單嗎?或者只是快捷方式?我想看看..我需要像全局的'工具'菜單,插件可以隨意添加子菜單 - 甚至可以在xaml中完成嗎?同樣它也可以,它會讓xaml代碼亂扔垃圾,不是嗎?現在我需要添加一個菜單命令就是所示的代碼。這是儘可能簡短和方便,它可以得到和它的工作美麗。順便說一下,你的磚牆在兩個方向上工作:我還沒有看到一個大規模的應用程序,沒有在代碼中定義單個UX部分。這是一個神話。 – stijn 2014-04-16 08:21:34

+0

你是對的 - 我曾經看到一些相當大的WPF UX項目,他們努力避免任何代碼 - 並且不必要的沉默。我嘗試只使用任何一種方法,最簡單。 這裏是一個示例代碼片段(赦免缺乏中文 - 我不確定如何格式化這個網站).. '

JamesWHurst 2014-04-16 10:48:15

+1

編輯你的答案,粘貼代碼,選擇它,然後單擊*代碼示例*按鈕。 – stijn 2014-04-16 10:55:21