2009-03-16 12 views

Respuesta

22

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 el modelo de vista, ya que la tendencia es definir un comando enrutado como una clase anidada dentro del modelo de vista. La funcionalidad de los dos es por lo demás similar.

67

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 M-V-VM, un RelayCommand (DelegateCommand in Prism) es probablemente la mejor opción.

34

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

Localización de código

RelayCommand le permite implementar el comando en cualquier clase (como ICommand-propiedad con delegados), que luego se enlaza convencionalmente al control, que invoca el comando. Esta clase es ViewModel. Si usa un comando enrutado, tendrá que 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.

Qué RS Conley dijo que RelayCommand le permite definir la RelayCommand fuera del modelo de vista es correcto, pero primero de todo es que le permite definir que dentro del modelo de vista, que RoutedCommand no lo hace.

enrutamiento

Por otro lado, RelayCommands no soportan el encaminamiento a través del árbol (como se ha dicho antes), que no es un problema, siempre y cuando su interfaz se basa en un único modelo de vista. 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 se pueden usar en MVVM estricto. Los RelayCommands son perfectos para MVVM pero no son compatibles con el enrutamiento, que puede necesitar.

+0

Gracias por la profundidad adicional en su explicación y la referencia a CompositeCommands, eso me ha ayudado a ver dónde encajan. –

13

Argumentarí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 utilizar un RoutedCommand dentro de un marco estricto MVVM se podía seguir estos pasos:

  1. Declarar una instancia RoutedCommand estática 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. Fije las vistas deseadas al uso de XAML RoutedCommand:

    <Button Command="{x:Static local:MyCommands.MyCustomCommand}" /> 
    
  3. Uno de sus puntos de vista que está unido a un ViewModel adecuado (es decir, el que sea ViewModel implementa la funcionalidad de comandos) necesidades para exponer una DependencyProperty costumbre que se une a su puesta en práctica del modelo de vista:

    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. Th e misma vista debería obligarse a la 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 para la vista los controladores de eventos asociados se acaba de delegar en el ICommand de 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. por último, vincular a su puesta en práctica del modelo de vista de comandos (que debe ser un ICommand) a la propiedad de dependencia costumbre 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 se puede conectar a él a través del RoutedCommand sin necesidad de ser 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().