2009-08-15 73 views
6

我有一個靜態類,其中包含一個我想用於綁定的RoutedUICommand。綁定到不在代碼隱藏的路由UICommand

public static class CommandLibrary 
{ 
    public static ProjectViewModel Project { get; set; } 

    public static RoutedUICommand AddPage { get; private set; } 

    static CommandLibrary() 
    { 
     AddPage = new RoutedUICommand("AddPage", "AddPage", typeof(CommandLibrary)); 

    } 

    public static void AddPage_Executed(object sender, ExecutedRoutedEventArgs args) 
    { 
     Project.AddPage(); 
    } 

    public static void AddPage_CanExecute(object sender, CanExecuteRoutedEventArgs args) 
    { 
     // We need a project before we can add pages. 
     if (Project != null) 
     { 
      args.CanExecute = true; 
     } 
     else 
     { 
      // Did not find project, turning Add Page off. 
      args.CanExecute = false; 
     } 
    } 
} 

當我試圖創建一個針對的CommandBinding這AddPage命令,VS拋出發脾氣,抱怨它不能在窗口1找到AddPage_CanExecute ...這是沒有意義的考慮,所有的例子我見過表明這一點XAML應該是罰款考慮的代碼我在的地方:

<Window x:Class="MyProject.Window1" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:MyProject"> 
    <Menu> 
     <Menu.CommandBindings> 
      <CommandBinding Command="local:CommandLibrary.AddPage" 
          Executed="AddPage_Executed" CanExecute="AddPage_CanExecute" /> 
     </Menu.CommandBindings> 
     <MenuItem Header="_Page"> 
      <MenuItem Header="_New" Command="local:CommandLibrary.AddPage" /> 
     </MenuItem> 
    </Menu> 
</Window> 

我也試過不包括Menu.CommandBindings部分,簡單地使用這個(按this question這表明這一點,但不是具體的):

<MenuItem Header="_New" Command="{x:Static local:CommandLibrary.AddPage}" /> 

這樣可以減少錯誤的發生,但它生成的菜單項總是被禁用! CanExecute似乎永遠不會被調用。我假設綁定在這種情況下也失敗了,儘管更安靜。

爲什麼VS憎恨我的命令並拒絕在正確的地方查找Executed和CanExecute方法?我見過很多例子(在Matthew McDonald的Pro WPF中,以及幾個在線自定義命令教程),我已經這樣做了。

回答

11

A CommandBinding就像您的可視化樹中的任何其他元素。其上指定的任何事件都將由您的可視樹的根部處理(在這種情況下,您的Window)。這意味着如果您將AddPage_ExecutedAddPage_CanExecute移動到您的Window代碼後面,它就會起作用。這允許您在許多UI組件中使用相同的命令,但具有不同的處理程序。

但是,我看到您的命令針對您的視圖模型執行了一些邏輯。爲了節省您一些時間和挫折感,請了解路由命令在這裏是錯誤的解決方案。取而代之的是,在您的視圖模型是這樣的封裝你的命令:

public class ProjectViewModel 
{ 
    private readonly ICollection<PageViewModel> _pages; 
    private readonly ICommand _addPageCommand; 

    public ProjectViewModel() 
    { 
     _pages = new ObservableCollection<PageViewModel>(); 
     _addPageCommand = new DelegateCommand(AddPage); 
    } 

    public ICommand AddPageCommand 
    { 
     get { return _addPageCommand; } 
    } 

    private void AddPage(object state) 
    { 
     _pages.Add(new PageViewModel()); 
    } 
} 

一個DelegateCommandICommand實現調用委託執行和查詢命令。這意味着命令邏輯全部包含在命令中,並且不需要CommandBinding來提供處理程序(根本不需要CommandBinding)。所以,你的看法剛剛綁定到你的虛擬機,如下所示:

<MenuItem Header="_New" Command="{Binding AddPageCommand}"/> 

我建議你通過這一系列文章的閱讀,給你更多的上下文:

+0

很棒的答案。讓我知道我需要什麼。我已經閱讀了一些MVVM教程,並看過這種Command使用過​​,但不記得如何做,所以我訴諸於我在書中找到的解決方案,並通過搜索。謝謝你的幫助。 – evizaer 2009-08-15 17:46:56

+0

美麗。我在這一塊上敲了敲頭...學習wpf + mvvm並不像我所希望的那樣直截了當。 RoutedUICommands對於我的意圖太複雜,我知道應該有一個更簡單的方法。 @Kent,感謝你的例子和博客。 – 2009-10-30 05:46:10