MVVM 路由和中继命令

Posted

技术标签:

【中文标题】MVVM 路由和中继命令【英文标题】:MVVM Routed and Relay Command 【发布时间】:2010-10-13 14:17:39 【问题描述】:

RoutedCommand 和 RelayCommand 有什么区别? 在 MVVM 模式中何时使用 RoutedCommand 以及何时使用 RelayCommand?

【问题讨论】:

【参考方案1】:

RoutedCommand 是 WPF 的一部分,而 RelayCommand 是由 WPF 门徒 Josh Smith 创建的;)。

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

【讨论】:

【参考方案2】:

关于在 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,但不支持您可能需要的路由。

【讨论】:

感谢您在解释中提供的额外深度以及对 CompositeCommands 的引用——这帮助我了解了它们的适用范围。【参考方案3】:

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

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

【讨论】:

【参考方案4】:

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

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

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

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

    public static class MyCommands 
        public static RoutedCommand MyCustomCommand = new RoutedCommand();
    
    

    使用 XAML 将所需的视图附加到 RoutedCommand:

    <Button Command="x:Static local:MyCommands.MyCustomCommand" />
    

    绑定到合适 ViewModel 的视图(即实现命令功能的任何 ViewModel)需要公开将绑定到 ViewModel 实现的自定义 DependencyProperty:

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

    同一视图应将自身绑定到步骤 1 中的 RoutedCommand。在 XAML 中:

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

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

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

    最后,将 ViewModel 的命令实现(应该是 ICommand)绑定到 XAML 中的自定义依赖属性:

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

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

不幸的是,ICommand.CanExecuteChanged 事件将不起作用。当您的 ViewModel 希望 View 刷新 CanExecute 属性时,您必须调用 CommandManager.InvalidateRequerySuggested()。

【讨论】:

以上是关于MVVM 路由和中继命令的主要内容,如果未能解决你的问题,请参考以下文章

思科模拟器做dhcp,一台pc,一台路由器做中继,一台路由器做服务器,求配置命令

ensp小实验走起来(路由下发MSTPVRRPDHCPDHCP中继NAT链路聚合)之配置

华硕路由器作中继设置,跪求。

网卡、中继器、网桥、交换器、集线器、路由器、网关的英语称呼

tplink路由器740n中继怎么设置

有wifi信号但弱,想用无线路由中继放大怎么设置?