什么是之间的差异的RoutedCommand和RelayCommand?何时使用RoutedCommand以及何时以MVVM模式使用RelayCommand?
什么是之间的差异的RoutedCommand和RelayCommand?何时使用RoutedCommand以及何时以MVVM模式使用RelayCommand?
Answers:
RoutedCommand是WPF的一部分,而RelayCommand是由WPF门徒Josh Smith;)创建的。
但是,认真地讲,RS Conley描述了其中的一些区别。关键区别在于RoutedCommand是一个ICommand实现,它使用RoutedEvent在树中进行路由,直到找到该命令的CommandBinding,而RelayCommand不进行路由,而是直接执行某些委托。在MV-VM场景中,RelayCommand(Prism中的DeletegateCommand)可能是更好的选择。
关于在MVVM中使用RelayCommand和RoutedCommand,对我而言主要区别如下:
代码位置
RelayCommand允许您在任何类中实现命令(如具有委托的ICommand属性),然后按常规将其数据绑定到调用该命令的控件。此类是ViewModel。如果使用路由命令,则必须在控件的代码背后实现与该命令相关的方法,因为这些方法由CommandBinding-element的属性指定。假设严格的MVVM意味着在文件后有一个“空”代码,那么实际上就不可能在MVVM中使用标准的路由命令。
RS Conley说的话,RelayCommand允许您在ViewModel之外定义RelayCommand,但是首先,您可以在内部定义它。在ViewModel,而RoutedCommand则不行。
路由
另一方面,RelayCommands不支持通过树的路由(如前所述),只要您的接口基于单个viewModel,这就不成问题。如果不是,例如,如果您有一个具有自己的viewModels的项目集合,并且想一次从父元素中为每个项目调用子ViewModel的命令,则必须使用路由(另请参见CompositeCommands) 。
总而言之,我要说的是,标准RoutedCommands在严格的MVVM中不可用。RelayCommands非常适合MVVM,但不支持您可能需要的路由。
我认为在严格的MVVM中,RoutedCommands是完全合法的。尽管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实现命令功能)都需要公开自定义DependencyProperty,该自定义DependencyProperty将绑定到ViewModel的实现:
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()。