Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
WPF:使用绑定在UserControl中的命令_Wpf_Binding_User Controls - Fatal编程技术网

WPF:使用绑定在UserControl中的命令

WPF:使用绑定在UserControl中的命令,wpf,binding,user-controls,Wpf,Binding,User Controls,我正在用MVVM做一个示例,但命令有问题。我有一个Article类(具有ID、名称、价格等)、一个表示视图模型的ArticleViewModel和一个允许输入文章数据的用户控件(ArticleControl),并绑定到ArticleViewModel的属性。此用户控件具有保存命令的投标 <UserControl.CommandBindings> <CommandBinding x:Name="saveCmd" Co

我正在用MVVM做一个示例,但命令有问题。我有一个Article类(具有ID、名称、价格等)、一个表示视图模型的ArticleViewModel和一个允许输入文章数据的用户控件(ArticleControl),并绑定到ArticleViewModel的属性。此用户控件具有保存命令的投标

   <UserControl.CommandBindings>
      <CommandBinding x:Name="saveCmd" 
                      Command="local:Commands.Save" 
                      CanExecute="CommandBinding_CanExecute"
                      Executed="CommandBinding_Executed"/>
   </UserControl.CommandBindings>
以及命令绑定处理程序:

  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时,命令被执行。但是,我也在该窗口上的该用户控件旁边放置了一个保存按钮。单击它时,我希望执行相同的命令(并且我不希望在承载用户控件的窗口中执行另一个命令绑定)


感谢您的帮助。谢谢。

我认为您只需将您的
CommandBinding
移动到一个资源字典,这样它就可以在您的用户控制之外使用了

保存按钮不会导致其他控件的commandbinding执行的原因是,保存按钮位于用户控件之外,因此命令系统不会在该控件中查找commandbinding。命令执行策略有点像冒泡事件,它将从关注的项(按钮)开始,并在可视化树上运行,直到找到CommandBindings

您可以在父控件中实现命令绑定,也可以将Save按钮的
CommandTarget
属性设置为用户控件


另一种方法是在按钮或按钮容器上设置
FocusManager.IsFocusScope=True
。如果您这样做,我建议您仔细阅读IsFocusScope的功能,但简而言之,当您按下按钮时,它会将输入焦点保留在任何具有焦点的控件上,而不是使按钮成为新的输入焦点。这通常用于工具栏或类似菜单的结构。

以下是我在工作中所做的,尽管我对这个解决方案不是特别满意。如果有人知道更好的方法,请告诉我

我将命令处理程序的逻辑移动到一个单独的静态类中:

   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>
然后我在使用控件的窗口中做了同样的操作

<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>

这是可行的,只有当字段填写正确并且单击按钮时正确执行命令时,“保存”按钮才会启用。

根据Patrick的建议,我就是这样做的:

  • 将命令绑定放在用户控件中,并在代码中实现处理程序,如原始消息所示

  • 使用按钮上的
    命令
    命令目标
    焦点管理器
    属性指向用户控件的绑定(
    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>
    
    
    
    你能给我举个例子吗?我尝试过为按钮设置
    Command=“local:Commands.Save”
    CommandTarget=“{Binding ElementName=ArticleUserControl}
    ,但不起作用。按钮一直处于禁用状态。您还可以在按钮上设置一个焦点管理器。IsFocusScope=True。尝试过,但没有起作用,正如我在下面的回答中所解释的(无法将代码发布到注释,注释的大小也受到限制)。
       <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);
      }
    
    <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>