MVVM маршрутизируемая и релейная команда - PullRequest
75 голосов
/ 16 марта 2009

В чем разница между RoutedCommand и RelayCommand ? Когда использовать RoutedCommand и когда использовать RelayCommand в шаблоне MVVM?

Ответы [ 4 ]

68 голосов
/ 19 марта 2009

RoutedCommand является частью WPF, в то время как RelayCommand был создан WPF Disciple, Джош Смит;).

Серьезно, однако, Р.С. Конли описал некоторые различия. Основное отличие состоит в том, что RoutedCommand является реализацией ICommand, которая использует RoutedEvent для маршрутизации по дереву до тех пор, пока не будет найдено CommandBinding для команды, тогда как RelayCommand не выполняет маршрутизацию и вместо этого напрямую выполняет некоторый делегат. В сценарии M-V-VM, возможно, лучшим вариантом является RelayCommand (DelegateCommand в Prism).

34 голосов
/ 22 июня 2011

Относительно использования RelayCommand и RoutedCommand в MVVM для меня главное отличие заключается в следующем:

Расположение кода

RelayCommand позволяет вам реализовать команду в любом классе (как свойство ICommand с делегатами), который затем традиционно привязывается к элементу управления, который вызывает команду. Этот класс является ViewModel . Если вы используете маршрутизируемую команду, вам придется реализовать методы, связанные с этой командой, в codebehind элемента управления, потому что методы определяются атрибутами атрибута CommandBinding-element. Предполагается, что строгий MVVM означает наличие «пустого» codebehind-файла, фактически нет возможности использовать стандартные маршрутизируемые команды с MVVM.

То, что сказал Р. Конли, что RelayCommand позволяет вам определять RelayCommand вне ViewModel, верно, но в первую очередь это позволяет вам определить его внутри ViewModel, а RoutedCommand - нет.

Маршрутизация

С другой стороны, RelayCommands не поддерживают маршрутизацию через дерево (как сказано выше), что не является проблемой, если ваш интерфейс основан на одной viewModel. Если это не так, например, если у вас есть коллекция элементов с их собственными viewModel и вы хотите вызвать команду дочернего ViewModel для каждого элемента сразу из родительского элемента, вам придется использовать маршрутизацию (см. Также CompositeCommands) .

В целом, я бы сказал, что стандартные RoutedCommands не могут использоваться в строгом MVVM. Команды RelayCommands идеально подходят для MVVM, но не поддерживают маршрутизацию, которая может вам понадобиться.

22 голосов
/ 16 марта 2009

Разница в том, что RelayCommand может принимать делегатов. Вы можете определить RelayCommand вне ViewModel. Затем ViewModel может добавить делегатов в команду при ее создании и привязать команду к объекту пользовательского интерфейса, например к элементу управления. В свою очередь, делегаты могут получить доступ к закрытой переменной ViewModel, как они определены в области действия самой модели представления.

Он используется для сокращения объема кода, содержащегося в ViewModel, поскольку тенденция заключается в определении команды Routed как вложенного класса внутри ViewModel. В остальном функциональность обоих аналогична.

14 голосов
/ 17 июля 2012

Я бы сказал, что RoutedCommands абсолютно законны в строгом MVVM. Хотя RelayCommands часто предпочтительнее из-за своей простоты, RoutedCommands иногда предлагают организационные преимущества. Например, вам может потребоваться подключить несколько разных представлений к общему экземпляру ICommand, не подвергая эту команду непосредственному представлению базовых ViewModels.

В качестве примечания помните, что строгий MVVM не запрещает использование кода-за. Если бы это было так, то вы никогда не могли бы определять пользовательские свойства зависимостей в своих представлениях!

Чтобы использовать RoutedCommand в строгой среде MVVM, вы можете выполнить следующие шаги:

  1. Объявите статический экземпляр RoutedCommand для вашей пользовательской команды. Вы можете пропустить этот шаг, если планируете использовать предопределенную команду из класса ApplicationCommands. Например:

    public static class MyCommands {
        public static RoutedCommand MyCustomCommand = new RoutedCommand();
    }
    
  2. Присоедините требуемые виды к RoutedCommand, используя XAML:

    <Button Command="{x:Static local:MyCommands.MyCustomCommand}" />
    
  3. Одно из ваших представлений, которое связано с подходящей ViewModel (то есть независимо от того, какая ViewModel реализует функциональность команды), должно предоставить пользовательский 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); }
        }
    
  4. То же представление должно связываться с RoutedCommand из шага 1. В XAML:

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

    В коде для вашего представления связанные обработчики событий просто делегируют ICommand из свойства зависимостей, объявленного на шаге 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. Наконец, свяжите реализацию команды ViewModel (которая должна быть ICommand) со свойством пользовательской зависимости в XAML:

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

Преимущество этого подхода заключается в том, что вашему ViewModel нужно только обеспечить единственную реализацию интерфейса ICommand (и это может быть даже RelayCommand), в то время как любое количество представлений может подключаться к нему через RoutedCommand без необходимости прямого подключения. привязан к этой модели представления.

К сожалению, есть недостаток в том, что событие ICommand.CanExecuteChanged не будет работать. Когда ваша ViewModel хочет, чтобы View обновил свойство CanExecute, вы должны вызвать CommandManager.InvalidateRequerySuggested ().

...