RoutedCommand と RelayCommand の違いは何ですか? RoutedCommandを使用するタイミングとMVVMパターンでRelayCommandを使用するタイミング
RoutedCommand はWPFの一部ですが、 RelayCommand はWPF Disciple、Josh Smithによって作成されました;)。
しかし、真剣に、RSコンリーはいくつかの違いを説明しました。主な違いは、RoutedCommandは、コマンドのCommandBindingが見つかるまでRoutedEventを使用してツリーをルーティングするICommand実装であり、RelayCommandはルーティングを行わず、代わりに一部のデリゲートを直接実行することです。 M-V-VMシナリオでは、RelayCommand(PrismのDelegateCommand)がおそらくすべての方が優れた選択肢です。
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に最適ですが、必要な場合があるルーティングをサポートしていません。
違いは、RelayCommandはデリゲートを受け入れることができることです。 ViewModelの外部でRelayCommandを定義できます。 ViewModelは、コマンドを作成してコントロールのようなUIオブジェクトにバインドするときに、デリゲートをコマンドに追加できます。デリゲートは、View Model自体のスコープで定義されているように、ViewModelのプライベート変数にアクセスできます。
これは、ViewModel内のネストされたクラスとしてRoutedコマンドを定義する傾向があるため、ViewModelに含まれるコードの量を削減するために使用されます。それ以外は、2つの機能は似ています。
RoutedCommandsは厳密なMVVMで完全に合法であると主張します。多くの場合、RelayCommandsがシンプルであることが望ましいのですが、RoutedCommandsは組織的な利点を提供する場合があります。たとえば、基になるViewModelにコマンドを直接公開せずに、複数の異なるビューを共有ICommandインスタンスに接続したい場合があります。
サイドノートとして、厳密なMVVMは分離コードの使用を禁止しないことに注意してください。もしそうなら、ビューでカスタム依存関係プロパティを定義することはできません!
厳格なMVVMフレームワーク内でRoutedCommandを使用するには、次の手順を実行できます。
カスタムコマンドの静的RoutedCommandインスタンスを宣言します。 ApplicationCommandsクラスの定義済みコマンドを使用する場合は、この手順をスキップできます。例えば:
public static class MyCommands {
public static RoutedCommand MyCustomCommand = new RoutedCommand();
}
XAMLを使用して、必要なビューをRoutedCommandにアタッチします。
<Button Command="{x:Static local:MyCommands.MyCustomCommand}" />
適切な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); }
}
同じビューは、ステップ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);
}
}
最後に、ViewModelのコマンド実装(ICommandである必要があります)をXAMLのカスタム依存関係プロパティにバインドします。
<local:MainView DataContext="{Binding MainViewModel}"
MyCustomCommand="{Binding CustomCommand}" />
このアプローチの利点は、ViewModelがICommandインターフェイスの単一の実装(およびRelayCommandでさえ可能)を提供するだけでよいのに対し、任意の数のビューがそれに直接バインドされる必要なくRoutedCommandを介してそれに接続できることです。 ViewModel。
残念ながら、ICommand.CanExecuteChangedイベントが機能しないという欠点があります。 ViewModelがViewにCanExecuteプロパティを更新することを望む場合、CommandManager.InvalidateRequerySuggested()を呼び出す必要があります。