MVVM 路由和中继命令

发布于 2024-07-15 13:04:43 字数 300 浏览 5 评论 0原文

RoatedCommand 和 < a href="http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090051" rel="noreferrer">RelayCommand ? 在 MVVM 模式中何时使用 RoutedCommand 以及何时使用 RelayCommand ?

What is the Difference between the RoutedCommand and RelayCommand ?
When to use RoutedCommand and when to use RelayCommand in MVVM pattern ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

寂寞花火° 2024-07-22 13:04:43

RoatedCommand 是 WPF 的一部分,而 RelayCommand 由 WPF 弟子 Josh Smith 创建;)。

不过,说实话,RS Conley 描述了一些差异。 主要区别在于 RoutedCommand 是一个 ICommand 实现,它使用 RoutedEvent 在树中进行路由,直到找到该命令的 CommandBinding,而 RelayCommand 不进行路由,而是直接执行一些委托。 在 MV-VM 场景中,RelayCommand(Prism 中的 DelegateCommand)可能是更好的选择。

RoutedCommand is part of WPF, while RelayCommand was created by a WPF Disciple, Josh Smith ;).

Seriously, though, RS Conley described some of the differences. The key difference is that RoutedCommand is an ICommand implementation that uses a RoutedEvent to route through the tree until a CommandBinding for the command is found, while RelayCommand does no routing and instead directly executes some delegate. In a M-V-VM scenario a RelayCommand (DelegateCommand in Prism) is probably the better choice all around.

戒ㄋ 2024-07-22 13:04:43

关于在 MVVM 中使用 RelayCommand 和 RoutedCommand,对我来说主要区别如下:

代码位置

RelayCommand 允许您在任何类中实现命令(作为带有委托的 ICommand 属性),然后是通常将数据绑定到调用命令的控件。 这个类是ViewModel
如果使用路由命令,则必须在控件的代码隐藏中实现与该命令相关的方法,因为这些方法是由 CommandBinding 元素的属性指定的。 假设严格的 MVVM 意味着有一个“空”代码隐藏文件,实际上不可能在 MVVM 中使用标准路由命令。

RS Conley 所说的 RelayCommand 允许您在 ViewModel 外部定义 RelayCommand 是正确的,但首先它允许您在 ViewModel 内部定义它,而 RoutedCommand 则不允许。

路由

另一方面,RelayCommands 不支持通过树进行路由(如前所述),这不是问题,只要您的界面基于单个 viewModel。 如果不是,例如,如果您有一个具有自己的 viewModel 的项目集合,并且想要立即为父元素之外的每个项目调用子 ViewModel 的命令,则必须使用路由(另请参阅 CompositeCommands) 。

总而言之,我想说的是,标准 RoutedCommands 在严格的 MVVM 中不可用。 RelayCommands 非常适合 MVVM,但不支持您可能需要的路由。

Regarding the use of RelayCommand and RoutedCommand in MVVM the main difference for me is the following:

Location of code

RelayCommand allows you to implement the command in any class (as ICommand-property with delegates), which then is conventionally databound to the control, which invokes the command. This class is the ViewModel.
If you use a routed command, you will have to implement the methods related to the command in the codebehind of the control, because the methods are specified by the attributes of the CommandBinding-element. Assumed that strict MVVM means having an "empty" codebehind-file, there actually is no possibility of using standard routed commands with MVVM.

What RS Conley said, that RelayCommand allows you to define the RelayCommand outside the ViewModel is right, but first of all it allows you to define it inside the ViewModel, which RoutedCommand doesn't.

Routing

On the other hand, RelayCommands do not support routing through the tree (as said before), which is not a problem, as long as your interface is based on a single viewModel. If it is not, for example if you have a collection of items with their own viewModels and want to invoke a command of the child ViewModel for each item out of the parent element at once, you will have to use routing (see also CompositeCommands).

All in all, I would say, that standard RoutedCommands are not usable in strict MVVM. RelayCommands are perfect for MVVM but do not support routing, which you might need.

注定孤独终老 2024-07-22 13:04:43

不同之处在于 RelayCommand 可以接受委托。 您可以在 ViewModel 之外定义 RelayCommand。 然后,当 ViewModel 创建命令并将其绑定到 UI 对象(如控件)时,它可以向命令添加委托。 委托反过来可以访问 ViewModel 的私有变量,因为它们是在 View Model 本身的范围内定义的。

它用于减少 ViewModel 中包含的代码量,因为趋势是将 Routed 命令定义为 ViewModel 内的嵌套类。 两者的功能在其他方面相似。

The difference is that RelayCommand can accept delegates. You can define the RelayCommand outside of the ViewModel. The ViewModel can then add delegates to the command when it creates and binds the command to an UI object like a control. The delegates in turn can access the private variable of the ViewModel as they are defined in the scope of the View Model itself.

It is used to cut down on the amount of code contained in the ViewModel as the trend is to define a Routed command as a nested class inside the ViewModel. The functionality of the two is otherwise similar.

茶色山野 2024-07-22 13:04:43

我认为 RoutedCommands 在严格的 MVVM 中是完全合法的。 尽管 RelayCommands 通常因其简单性而更受青睐,但 RoutedCommands 有时也能提供组织优势。 例如,您可能希望多个不同的视图连接到共享 ICommand 实例,而不直接将该命令公开给底层 ViewModel。

附带说明一下,请记住严格的 MVVM 并不禁止使用代码隐藏。 如果这是真的,那么您永远无法在视图中定义自定义依赖项属性!

为了在严格的 MVVM 框架内使用 RoutedCommand,您可以按照以下步骤操作:

  1. 为您的自定义命令声明一个静态 RoutedCommand 实例。 如果您打算使用 ApplicationCommands 类中的预定义命令,则可以跳过此步骤。 例如:

    公共静态类 MyCommands { 
          公共静态 RoutedCommand MyCustomCommand = new RoutedCommand(); 
      } 
      
  2. 使用 XAML 将所需的视图附加到 RoutedCommand:

  3. 绑定到合适 ViewModel 的视图之一(即实现命令功能的 ViewModel)需要公开一个自定义 DependencyProperty,该属性将是绑定到您的 ViewModel 的实现:

    公共分部类MainView:UserControl 
      { 
          公共静态只读 DependencyProperty MyCustomCommandProperty = 
              DependencyProperty.Register("MyCustomCommand", 
              typeof(ICommand), typeof(MainView), new UIPropertyMetadata(null)); 
    
          公共 ICommand MyCustomCommand { 
              获取 { 返回 (ICommand)GetValue(MyCustomCommandProperty);   } 
              设置 { SetValue(MyCustomCommandProperty, 值);   } 
          } 
      
  4. 相同的视图应该将自身绑定到步骤 1 中的 RoutedCommand。在 XAML 中:

    ; 
          > 
       
      

    在视图的代码隐藏中,关联的事件处理程序将仅从步骤 3 中声明的依赖属性委托给 ICommand:

    private void MyCustomCommand_CanExecute(对象发送者,CanExecuteRoulatedEventArgs e){ 
          var 命令 = this.MyCustomCommand; 
          如果(命令!= null){ 
              e.已处理=真; 
              e.CanExecute = command.CanExecute(e.Parameter); 
          } 
      } 
      私人无效MyCustomCommand_Executed(对象发送者,ExecutedRoulatedEventArgs e){ 
          var 命令 = this.MyCustomCommand; 
          如果(命令!= null){ 
              e.已处理=真; 
              命令.执行(e.参数); 
          } 
      } 
      
  5. 最后,将 ViewModel 的命令实现(应该是 ICommand)绑定到 XAML 中的自定义依赖属性:

     
      

这种方法的优点是 ViewModel 只需要提供 ICommand 接口的单个​​实现(它甚至可以是 RelayCommand),而任意数量的 View 都可以通过 RoutedCommand 附加到它,而无需直接绑定到该 ViewModel。

不幸的是,有一个缺点,即 ICommand.CanExecuteChanged 事件将不起作用。 当您的 ViewModel 希望视图刷新 CanExecute 属性时,您必须调用 CommandManager.InvalidateRequerySuggested()。

I would argue that RoutedCommands are perfectly legal in strict MVVM. Although RelayCommands are often preferable for their simplicity, RoutedCommands sometimes offer organizational advantages. For example, you might want several different views to connect to a shared ICommand instance without directly exposing that command to the underlying ViewModels.

As a side note, remember that strict MVVM does not prohibit the use of code-behind. If that were true then you could never define custom dependency properties in your views!

In order to use a RoutedCommand within a strict MVVM framework you could follow these steps:

  1. Declare a static RoutedCommand instance for your custom command. You can skip this step if you plan to use a predefined command from the ApplicationCommands class. For example:

    public static class MyCommands {
        public static RoutedCommand MyCustomCommand = new RoutedCommand();
    }
    
  2. Attach the desired views to the RoutedCommand using XAML:

    <Button Command="{x:Static local:MyCommands.MyCustomCommand}" />
    
  3. One of your views which is bound to a suitable ViewModel (i.e. whichever ViewModel implements the command functionality) needs to expose a custom DependencyProperty which will be bound to your ViewModel's implementation:

    public partial class MainView : UserControl
    {
        public static readonly DependencyProperty MyCustomCommandProperty =
            DependencyProperty.Register("MyCustomCommand",
            typeof(ICommand), typeof(MainView), new UIPropertyMetadata(null));
    
        public ICommand MyCustomCommand {
            get { return (ICommand)GetValue(MyCustomCommandProperty); }
            set { SetValue(MyCustomCommandProperty, value); }
        }
    
  4. The same view should bind itself to the RoutedCommand from step 1. In the XAML:

    <UserControl.CommandBindings>
        <CommandBinding Command="{x:Static local:MyCommands.MyCustomCommand}"
                        CanExecute="MyCustomCommand_CanExecute"
                        Executed="MyCustomCommand_Executed"
                        />
    </UserControl.CommandBindings>
    

    In the code-behind for your view the associated event handlers will just delegate to the ICommand from the dependency property declared in step 3:

    private void MyCustomCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
        var command = this.MyCustomCommand;
        if (command != null) {
            e.Handled = true;
            e.CanExecute = command.CanExecute(e.Parameter);
        }
    }
    private void MyCustomCommand_Executed(object sender, ExecutedRoutedEventArgs e) {
        var command = this.MyCustomCommand;
        if (command != null) {
            e.Handled = true;
            command.Execute(e.Parameter);
        }
    }
    
  5. Finally, bind your ViewModel's command implementation (which should be an ICommand) to the custom dependency property in XAML:

    <local:MainView DataContext="{Binding MainViewModel}"
                    MyCustomCommand="{Binding CustomCommand}" />
    

The advantage of this approach is that your ViewModel only needs to provide a single implementation of the ICommand interface (and it can even be a RelayCommand), while any number of Views can attach to it via the RoutedCommand without needing to be directly bound to that ViewModel.

Unfortunately there is a downside in that the ICommand.CanExecuteChanged event will not work. When your ViewModel wants the View to refresh the CanExecute property then you must call CommandManager.InvalidateRequerySuggested().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文