example commandmanager mvvm command relaycommand routedcommand

mvvm - commandmanager - icommand wpf



Comando enrutado y relevador MVVM (4)

¿Cuál es la diferencia entre RoutedCommand y RelayCommand ? ¿Cuándo usar RoutedCommand y cuándo utilizar RelayCommand en el patrón MVVM?


En cuanto al uso de RelayCommand y RoutedCommand en MVVM, la principal diferencia para mí es la siguiente:

Ubicación del código

RelayCommand le permite implementar el comando en cualquier clase (como ICommand-property with deletes), que luego se enlaza convencionalmente con el control, que invoca el comando. Esta clase es ViewModel . Si usa un comando enrutado, deberá implementar los métodos relacionados con el comando en el código detrás del control, porque los métodos están especificados por los atributos del elemento CommandBinding. Se supone que MVVM estricto significa tener un archivo subyacente de código "vacío", en realidad no hay posibilidad de usar comandos enrutados estándar con MVVM.

Lo que RS Conley dijo, que RelayCommand le permite definir el RelayCommand fuera de ViewModel es correcto, pero antes que nada le permite definirlo dentro de ViewModel, que RoutedCommand no lo hace.

Enrutamiento

Por otro lado, RelayCommands no admite el enrutamiento a través del árbol (como se dijo antes), lo cual no es un problema, siempre y cuando su interfaz se base en un único viewModel. Si no es así, por ejemplo, si tiene una colección de elementos con sus propios modelos de vista y desea invocar un comando del modelo de vista hijo para cada elemento del elemento principal a la vez, tendrá que usar el enrutamiento (consulte también Comandos compuestos) .

Con todo, diría que los RoutedCommands estándar no son utilizables en MVVM estricto. Los RelayCommands son perfectos para MVVM pero no son compatibles con el enrutamiento, que puede necesitar.


La diferencia es que RelayCommand puede aceptar delegados. Puede definir el RelayCommand fuera del ViewModel. El ViewModel puede agregar delegados al comando cuando crea y vincula el comando a un objeto UI como un control. Los delegados a su vez pueden acceder a la variable privada de ViewModel, tal como están definidos en el alcance del propio View Model.

Se usa para reducir la cantidad de código contenido en ViewModel, ya que la tendencia es definir un comando enrutado como una clase anidada dentro de ViewModel. La funcionalidad de los dos es por lo demás similar.


Yo diría que los RoutedCommands son perfectamente legales en MVVM estricto. Aunque los RelayCommands a menudo son preferibles por su simplicidad, los RoutedCommands a veces ofrecen ventajas de organización. Por ejemplo, es posible que desee varias vistas diferentes para conectarse a una instancia de ICommand compartida sin exponer directamente ese comando a los ViewModels subyacentes.

Como nota al margen, recuerde que el estricto MVVM no prohíbe el uso de código subyacente. Si eso fuera cierto, ¡nunca podría definir propiedades de dependencia personalizadas en sus vistas!

Para usar un RoutedCommand dentro de un marco MVVM estricto, puede seguir estos pasos:

  1. Declare una instancia estática de RoutedCommand para su comando personalizado. Puede omitir este paso si planea usar un comando predefinido de la clase ApplicationCommands. Por ejemplo:

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

  2. Adjunte las vistas deseadas a RoutedCommand usando XAML:

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

  3. Una de las vistas que está vinculada a un modelo de vista adecuado (es decir, cualquiera que ViewModel implemente la funcionalidad del comando) necesita exponer una DependencyProperty personalizada que se vinculará a la implementación de su 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. La misma vista debe vincularse a RoutedCommand desde el paso 1. En el XAML:

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

    En el código subyacente de su vista, los controladores de eventos asociados simplemente delegarán a ICommand desde la propiedad de dependencia declarada en el paso 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. Finalmente, vincule la implementación del comando de ViewModel (que debería ser un ICommand) a la propiedad de dependencia personalizada en XAML:

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

La ventaja de este enfoque es que su ViewModel solo necesita proporcionar una implementación única de la interfaz de ICommand (e incluso puede ser un RelayCommand), mientras que cualquier número de Vistas puede conectarse a él a través del RoutedCommand sin necesidad de estar directamente vinculado a ese ViewModel.

Desafortunadamente, hay un inconveniente en que el evento ICommand.CanExecuteChanged no funcionará. Cuando su ViewModel quiere que View actualice la propiedad CanExecute, debe llamar a CommandManager.InvalidateRequerySuggested ().


RoutedCommand es parte de WPF, mientras que RelayCommand fue creado por un WPF Disciple, Josh Smith;).

En serio, sin embargo, RS Conley describió algunas de las diferencias. La diferencia clave es que RoutedCommand es una implementación de ICommand que usa un RoutedEvent para enrutar a través del árbol hasta que se encuentra un CommandBinding para el comando, mientras que RelayCommand no enruta y en su lugar ejecuta directamente algún delegado. En un escenario MV-VM, un RelayCommand (DelegateCommand in Prism) es probablemente la mejor opción.