2011-05-04 52 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>