77

RoutedCommandRelayCommandの違いは何ですか? RoutedCommand をいつ使用し、MVVM パターンで RelayCommand を使用するのはいつですか?

4

4 に答える 4

35

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

コードの場所

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

RS Conley が言ったこと、RelayCommand を使用すると、ViewModel の外部で RelayCommand を定義できますが、まず第一に、RoutedCommand では定義できないViewModel の内部で定義できます。

ルーティング

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

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

于 2011-06-22T14:21:24.417 に答える
22

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

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

于 2009-03-16T12:53:47.967 に答える
15

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 にバインドされているビューの 1 つ (つまり、ViewModel がコマンド機能を実装しているもの) は、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 を介して任意の数のビューをアタッチできることです。ビューモデル。

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

于 2012-07-17T19:30:22.270 に答える