web-dev-qa-db-ja.com

MVVMルーティングおよびリレーコマンド

RoutedCommandRelayCommand の違いは何ですか? RoutedCommandを使用するタイミングとMVVMパターンでRelayCommandを使用するタイミング

75
user72799

RoutedCommand はWPFの一部ですが、 RelayCommand はWPF Disciple、Josh Smithによって作成されました;)。

しかし、真剣に、RSコンリーはいくつかの違いを説明しました。主な違いは、RoutedCommandは、コマンドのCommandBindingが見つかるまでRoutedEventを使用してツリーをルーティングするICommand実装であり、RelayCommandはルーティングを行わず、代わりに一部のデリゲートを直接実行することです。 M-V-VMシナリオでは、RelayCommand(PrismのDelegateCommand)がおそらくすべての方が優れた選択肢です。

68
wekempf

MVVMでのRelayCommandとRoutedCommandの使用に関して、主な違いは次のとおりです。

コードの場所

RelayCommandを使用すると、任意のクラスにコマンドを実装できます(デリゲートを持つICommandプロパティとして)。これは、通常、コマンドに呼び出されるコントロールにデータバインドされます。このクラスはViewModelです。ルーティングされたコマンドを使用する場合、コントロールのcodebehindでコマンドに関連するメソッドを実装する必要があります。メソッドはCommandBinding要素の属性。厳密なMVVMが「空の」コードビハインドファイルを持つことを意味すると仮定すると、MVVMで標準のルーティングコマンドを使用する可能性は実際にはありません。

RS Conleyが言ったこと、RelayCommandはViewModelの外でRelayCommandを定義することができますが、まず最初にViewModelをinside定義することができます、RoutedCommandにはありません。

ルーティング

一方、RelayCommandsは、前述のようにツリーを介したルーティングをサポートしていません。これは、インターフェイスが単一のviewModelに基づいている限り、問題ではありません。そうでない場合、たとえば、独自のviewModelを持つアイテムのコレクションがあり、親要素から各アイテムの子ViewModelのコマンドを一度に呼び出したい場合、ルーティングを使用する必要があります(CompositeCommandsも参照) 。

概して、標準のRoutedCommandsは厳密なMVVMでは使用できないと言います。 RelayCommandsはMVVMに最適ですが、必要な場合があるルーティングをサポートしていません。

34
Marc

違いは、RelayCommandはデリゲートを受け入れることができることです。 ViewModelの外部でRelayCommandを定義できます。 ViewModelは、コマンドを作成してコントロールのようなUIオブジェクトにバインドするときに、デリゲートをコマンドに追加できます。デリゲートは、View Model自体のスコープで定義されているように、ViewModelのプライベート変数にアクセスできます。

これは、ViewModel内のネストされたクラスとしてRoutedコマンドを定義する傾向があるため、ViewModelに含まれるコードの量を削減するために使用されます。それ以外は、2つの機能は似ています。

22
RS Conley

RoutedCommandsは厳密なMVVMで完全に合法であると主張します。多くの場合、RelayCommandsがシンプルであることが望ましいのですが、RoutedCommandsは組織的な利点を提供する場合があります。たとえば、基になるViewModelにコマンドを直接公開せずに、複数の異なるビューを共有ICommandインスタンスに接続したい場合があります。

サイドノートとして、厳密なMVVMは分離コードの使用を禁止しないことに注意してください。もしそうなら、ビューでカスタム依存関係プロパティを定義することはできません!

厳格なMVVMフレームワーク内でRoutedCommandを使用するには、次の手順を実行できます。

  1. カスタムコマンドの静的RoutedCommandインスタンスを宣言します。 ApplicationCommandsクラスの定義済みコマンドを使用する場合は、この手順をスキップできます。例えば:

    public static class MyCommands {
        public static RoutedCommand MyCustomCommand = new RoutedCommand();
    }
    
  2. XAMLを使用して、必要なビューをRoutedCommandにアタッチします。

    <Button Command="{x:Static local:MyCommands.MyCustomCommand}" />
    
  3. 適切なViewModel(つまり、コマンド機能を実装するViewModel)にバインドされているビューの1つは、ViewModelの実装にバインドされるカスタムDependencyPropertyを公開する必要があります。

    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. 同じビューは、ステップ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);
        }
    }
    
  5. 最後に、ViewModelのコマンド実装(ICommandである必要があります)をXAMLのカスタム依存関係プロパティにバインドします。

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

このアプローチの利点は、ViewModelがICommandインターフェイスの単一の実装(およびRelayCommandでさえ可能)を提供するだけでよいのに対し、任意の数のビューがそれに直接バインドされる必要なくRoutedCommandを介してそれに接続できることです。 ViewModel。

残念ながら、ICommand.CanExecuteChangedイベントが機能しないという欠点があります。 ViewModelがViewにCanExecuteプロパティを更新することを望む場合、CommandManager.InvalidateRequerySuggested()を呼び出す必要があります。

14
RogerN