75 votes

MVVM Routed and Relay Command (commande routée et relais)

Quelle est la différence entre la RoutedCommand y Commande de relais ? Quand utiliser RoutedCommand et quand utiliser RelayCommand dans le modèle MVVM ?

68voto

wekempf Points 2168

RoutedCommand fait partie de WPF, tandis que Commande de relais a été créé par un disciple de WPF, Josh Smith ;).

Plus sérieusement, RS Conley a décrit certaines des différences. La principale différence est que RoutedCommand est une implémentation de ICommand qui utilise un RoutedEvent pour parcourir l'arbre jusqu'à ce qu'un CommandBinding pour la commande soit trouvé, alors que RelayCommand ne fait pas de routage et exécute directement un délégué. Dans un scénario M-V-VM, une RelayCommand (DelegateCommand dans Prism) est probablement le meilleur choix possible.

34voto

Marc Points 4481

En ce qui concerne l'utilisation de RelayCommand et RoutedCommand dans MVVM, la principale différence pour moi est la suivante :

Emplacement du code

RelayCommand vous permet d'implémenter la commande dans n'importe quelle classe (en tant que propriété ICommand avec des délégués), qui est alors conventionnellement liée au contrôle qui invoque la commande. Cette classe est la classe Modèle de vue . Si vous utilisez une commande routée, vous devrez implémenter les méthodes liées à la commande dans le fichier codebehind du contrôle, car les méthodes sont spécifiées par les attributs de l'élément CommandBinding. En supposant que MVVM strict signifie avoir un fichier de code "vide", il n'y a en fait aucune possibilité d'utiliser des commandes routées standard avec MVVM.

Ce que RS Conley a dit, à savoir que RelayCommand vous permet de définir la commande de relais en dehors du ViewModel, est exact, mais tout d'abord, il vous permet de la définir à l'intérieur le ViewModel, ce qui n'est pas le cas de RoutedCommand.

Routage

D'autre part, les RelayCommands ne prennent pas en charge le routage à travers l'arbre (comme indiqué précédemment), ce qui n'est pas un problème, tant que votre interface est basée sur un seul viewModel. Si ce n'est pas le cas, par exemple si vous avez une collection d'éléments avec leurs propres ViewModels et que vous voulez invoquer une commande du ViewModel enfant pour chaque élément à partir de l'élément parent en une seule fois, vous devrez utiliser le routage (voir aussi CompositeCommands).

En résumé, je dirais que les RoutedCommands standard ne sont pas utilisables dans le cadre d'un MVVM strict. Les RelayCommands sont parfaites pour MVVM mais ne supportent pas le routage, ce dont vous pourriez avoir besoin.

22voto

RS Conley Points 6268

La différence est que RelayCommand peut accepter des délégués. Vous pouvez définir la RelayCommand en dehors du ViewModel. Le ViewModel peut alors ajouter des délégués à la commande lorsqu'il crée et lie la commande à un objet d'interface utilisateur tel qu'un contrôle. Les délégués peuvent à leur tour accéder aux variables privées du ViewModel car elles sont définies dans la portée du ViewModel lui-même.

Elle est utilisée pour réduire la quantité de code contenue dans le ViewModel car la tendance est de définir une commande Routed comme une classe imbriquée dans le ViewModel. La fonctionnalité des deux est par ailleurs similaire.

15voto

RogerN Points 67

Je dirais que les RoutedCommands sont parfaitement légales dans le cadre d'un MVVM strict. Bien que les RelayCommands soient souvent préférables pour leur simplicité, les RoutedCommands offrent parfois des avantages organisationnels. Par exemple, vous pouvez vouloir que plusieurs vues différentes se connectent à une instance ICommand partagée sans exposer directement cette commande aux ViewModels sous-jacents.

Par ailleurs, n'oubliez pas que MVVM strict n'interdit pas l'utilisation de code-behind. Si c'était le cas, vous ne pourriez jamais définir des propriétés de dépendance personnalisées dans vos vues !

Pour utiliser une RoutedCommand dans un cadre MVVM strict, vous pouvez suivre les étapes suivantes :

  1. Déclarez une instance statique de RoutedCommand pour votre commande personnalisée. Vous pouvez sauter cette étape si vous prévoyez d'utiliser une commande prédéfinie de la classe ApplicationCommands. Par exemple, vous pouvez déclarer une instance de RoutedCommand statique pour votre commande personnalisée :

    public static class MyCommands {
        public static RoutedCommand MyCustomCommand = new RoutedCommand();
    }
  2. Attachez les vues souhaitées à la RoutedCommand à l'aide de XAML :

    <Button Command="{x:Static local:MyCommands.MyCustomCommand}" />
  3. L'une de vos vues liées à un ViewModel approprié (c'est-à-dire le ViewModel qui implémente la fonctionnalité de commande) doit exposer une DependencyProperty personnalisée qui sera liée à l'implémentation de votre 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 même vue doit se lier à la RoutedCommand de l'étape 1. Dans le XAML :

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

    Dans le code-behind de votre vue, les gestionnaires d'événements associés seront simplement délégués à la commande IC de la propriété de dépendance déclarée à l'étape 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. Enfin, liez l'implémentation de la commande de votre ViewModel (qui doit être une ICommand) à la propriété de dépendance personnalisée dans XAML :

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

L'avantage de cette approche est que votre ViewModel ne doit fournir qu'une seule implémentation de l'interface ICommand (et il peut même s'agir d'une RelayCommand), tandis qu'un nombre quelconque de Views peuvent s'y attacher via RoutedCommand sans avoir besoin d'être directement liés à ce ViewModel.

Malheureusement, il y a un inconvénient : l'événement ICommand.CanExecuteChanged ne fonctionnera pas. Lorsque votre ViewModel souhaite que la vue rafraîchisse la propriété CanExecute, vous devez appeler CommandManager.InvalidateRequerySuggested().

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X