2011-05-04 72 views
3

我正在做一個MVVM的示例,並且遇到命令問題。我有一個Article類(具有ID,名稱,價格等),一個表示視圖模型的ArticleViewModel以及一個允許輸入文章數據的用戶控件(ArticleControl),並綁定到ArticleViewModel的屬性。此用戶控件具有保存命令的標識。WPF:使用在UserControl中綁定的命令

<UserControl.CommandBindings> 
     <CommandBinding x:Name="saveCmd" 
         Command="local:Commands.Save" 
         CanExecute="CommandBinding_CanExecute" 
         Executed="CommandBinding_Executed"/> 
    </UserControl.CommandBindings> 

這是命令是如何定義的:

public class Commands 
    { 
     private static RoutedUICommand _save; 
     public static RoutedUICommand Save 
     { 
     get { return _save; } 
     } 

     static Commands() 
     { 
     InputGestureCollection saveInputs = new InputGestureCollection(); 
     saveInputs.Add(new KeyGesture(Key.S, ModifierKeys.Control, "Ctrl+S")); 

     _save = new RoutedUICommand(
      "Save", 
      "Save", 
      typeof(Commands), 
      saveInputs); 
     } 
    } 

和命令綁定處理程序:

private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) 
    { 
    double baseprice = 0; 
    double.TryParse(ArticleBasePrice.Text, out baseprice); 

    e.CanExecute = 
     !string.IsNullOrEmpty(ArticleID.Text) && 
     !string.IsNullOrEmpty(ArticleName.Text) && 
     !string.IsNullOrEmpty(ArticleDescription.Text) && 
     baseprice > 0; 
    } 

    private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e) 
    { 
    ArticleViewModel avm = (ArticleViewModel)DataContext; 
    if (avm != null && avm.Save()) 
    { 
     ArticleID.Text = String.Empty; 
     ArticleName.Text = String.Empty; 
     ArticleDescription.Text = String.Empty; 
     ArticleBasePrice.Text = String.Empty; 
    } 
    } 

現在,我把這個用戶控件的窗口上。當我按下Ctrl + S時,命令被執行。但是,我還在該窗口上放置了一個Save按鈕,位於此用戶控件的旁邊。當我點擊它時,我想執行相同的命令(並且我不想在託管用戶控件的窗口中執行另一個命令綁定)。

<StackPanel> 
     <local:ArticleControl x:Name="articleControl" /> 
     <Button Name="btnSave" 
       Content="Save" Width="100" 
       HorizontalAlignment="Left" 
       Command="{???}"/> <!-- what should I put here? --> 
    </StackPanel> 

但我不知道如何引用在用戶控件中定義的saveCmd。我嘗試了不同的事情,有些完全錯誤(它們在運行應用程序時拋出異常),有些沒有任何效果。

Command="{StaticResource saveCmd}" 
Command="{StaticResource local:ArticleControl.saveCmd}" 
Command="{x:Static local:Commands.Save}" 

任何幫助表示讚賞。謝謝。

回答

3

保存按鈕不會導致其他控件的命令綁定執行的原因是因爲保存按鈕不在用戶控件中,因此命令系統不會在該控件中查找命令綁定。命令執行策略有點像一個冒泡事件,它將從關注的項目(按鈕)開始,然後沿着可視化樹直到找到CommandBindings。

您可以在父控件中實現命令綁定,也可以將Save按鈕的CommandTarget屬性設置爲用戶控件。

另一種方法是在按鈕或按鈕的容器上設置FocusManager.IsFocusScope=True。如果你這樣做,我建議你閱讀IsFocusScope做什麼,但簡而言之,它會將輸入焦點留在任何控制焦點,當你按下按鈕,而不是使按鈕成爲新的輸入焦點。這通常用於工具欄或菜單結構。

+0

你能舉個例子嗎?我嘗試了爲按鈕設置'Command =「local:Commands.Save」'和'CommandTarget =「{Binding ElementName = ArticleUserControl}',但它不起作用。該按鈕一直處於禁用狀態。 – 2011-05-05 06:43:35

+0

您也可以在按鈕上設置一個FocusManager.IsFocusScope = True。 – 2011-05-05 08:11:55

+0

太好了,工作正常。 – 2011-05-05 08:25:22

1

我認爲你只需要將你的CommandBinding移動到一個資源字典,這樣它就可以在你的UserControl之外使用!

+0

試過,但沒有工作,我在下面(不能發佈代碼的註釋,這也只限於一個答案解釋在尺寸方面)。 – 2011-05-05 08:21:37

0

以下是我所做的工作,儘管我對解決方案並不滿意。如果有人知道更好的方法,請讓我知道。

我移動的命令處理程序中的邏輯在一個單獨的,靜態類:

static class CommandsCore 
    { 
     public static bool Save_CanExecute(ArticleControl ac) 
     { 
     double baseprice = 0; 
     double.TryParse(ac.ArticleBasePrice.Text, out baseprice); 

     return 
      !string.IsNullOrEmpty(ac.ArticleID.Text) && 
      !string.IsNullOrEmpty(ac.ArticleName.Text) && 
      !string.IsNullOrEmpty(ac.ArticleDescription.Text) && 
      baseprice > 0; 
     } 

     public static void Save_Executed(ArticleControl ac) 
     { 
     ArticleViewModel avm = (ArticleViewModel)ac.DataContext; 
     if (avm != null && avm.Save()) 
     { 
      ac.ArticleID.Text = String.Empty; 
      ac.ArticleName.Text = String.Empty; 
      ac.ArticleDescription.Text = String.Empty; 
      ac.ArticleBasePrice.Text = String.Empty; 
     } 
     } 
    } 

我不停的命令在用戶控制結合,因爲它是

<UserControl.CommandBindings> 
     <CommandBinding x:Name="saveCmd" 
         Command="local:Commands.Save" 
         CanExecute="CommandBinding_CanExecute" 
         Executed="CommandBinding_Executed"/> 
    </UserControl.CommandBindings> 

但是在處理程序我稱爲上面定義的兩個方法。

public void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) 
    { 
    e.CanExecute = CommandsCore.Save_CanExecute(this); 
    } 

    public void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e) 
    { 
    CommandsCore.Save_Executed(this); 
    } 

然後我從使用控件的窗口做了同樣的操作。

<Window x:Class="MVVMModel.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:MVVMModel" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.CommandBindings> 
     <CommandBinding x:Name="saveCmd" 
         Command="local:Commands.Save" 
         CanExecute="CommandBinding_CanExecute" 
         Executed="CommandBinding_Executed"/> 
    </Window.CommandBindings> 

    <StackPanel> 
     <local:ArticleControl x:Name="articleControl" /> 
     <Button Name="btnSave" Content="Save" Width="100" HorizontalAlignment="Left" 
       Command="local:Commands.Save"/> 
    </StackPanel> 
</Window> 

和處理

public void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) 
    { 
    e.CanExecute = CommandsCore.Save_CanExecute(articleControl); 
    } 

    public void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e) 
    { 
    CommandsCore.Save_Executed(articleControl); 
    } 

而且這個作品中,保存按鈕被啓用,只有當字段在適當填充,然後點擊按鈕時命令被正確執行。

1

基於帕特里克的建議,這是我做的:

  1. 把命令,在用戶控件綁定並且如圖所示,原始消息在後臺代碼實現的處理程序。

  2. 使用上的按鈕CommandCommandTargetFocusManager屬性指向從用戶控制的結合(ArticleUserControl是用戶控制的x:Name)。

這是窗口中的XAML的樣子:

<Window x:Class="MVVMModel.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:MVVMModel" 
     Title="MainWindow" Height="350" Width="525"> 
    <StackPanel> 
     <local:ArticleControl x:Name="articleControl" /> 
     <Button Name="btnSave" Content="Save" Width="100" HorizontalAlignment="Left" 
       Command="local:Commands.Save" 
       CommandTarget="{Binding ElementName=ArticleUserControl}" 
       FocusManager.IsFocusScope="True" /> 
    </StackPanel> 
</Window>