web-dev-qa-db-ja.com

MVVMコマンド-すべてに対して1つのコマンドまたは複数のコマンド?

私の最後の会社では、ビューコマンドの処理に関して、ViewModelBaseに次のような1つの中心的なコマンドが実装されていました。

public ICommand ToolCommand { get; set; }

また、ViewModelBaseでは初期化されており、このコマンドにフックされているすべてのボタンは、コマンドパラメータによって区別されています。

public ViewModelBase()
{
    ToolCommand = new RelayCommand<String>(Execute, CanExecute);
}

ビューモデルベースでは、ExecuteおよびCanExecute関数は仮想であり(Closeなどの一般的なコマンドを実装するなど)、派生クラスでは、ExecuteおよびCanExecute関数は大きなスイッチであり、基本機能を拡張し、多かれ少なかれ見えましたこのような:

public void Execute(String parameter)
{
    switch (parameter)
    {
        case "Refresh":
          RefreshGrid();
          break;
        case "OtherStuff":
          Other();
          break;
        default:
          base.Execute(parameter);
    }
}

これらのケースでは、ボタンを追加した直後に、適切なビューモデルに別のスイッチケースを追加しました。

ただし、私の現在の会社では、各ボタンには次のような特定のコマンドプロパティがあるというルールがあります。

public ICommand RefreshCommand { get; set; }
public ICommand OtherStuffCommand { get; set; }

、1つずつ開始:

RefreshCommand = new RelayCommand<String>(RefreshGrid(), _canRefresh);
OtherStuffCommand = new RelayCommand<String>(OtherStuff(), _canDoOther);

オフィスでは、コンパクトさ、美しさ、デバッグのしやすさの点でどちらが優れているかについては同意できません。確かに、コストがかかるために作業部品を書き直すことはありませんが、新しいプロジェクトを検討すると、どちらがより有利であるかについて話し合うのは困難です。

これらの2つのアプローチのどちらが優れているのですか?

7
ermahgerd

文字列でswitchステートメントを使用することは、次の理由からひどい考えです。

  1. CommandParameterを使用してコマンド自体を識別しているため、コマンドは実際のパラメーターを受け取ることができません。
  2. ExecuteメソッドとCanExecuteメソッドは大きなBLOBになり、バインドされているすべてのXAMLファイルでViewModelを相互参照する必要があるため、実際にすべてのコマンドを処理しているかどうかを判断することはできません。
  3. 一部のコマンドはCanExecuteを必要としません。各コマンドを個別のプロパティとして持っている場合、CanExecuteをサポートするコマンドとサポートしないコマンドを簡単に区別できます。 switchステートメントを使用すると、それを判別するのが非常に難しくなります。
  4. 派生クラスの単一のコマンドの動作をオーバーライドすることは非常に困難です。子ViewModelクラスがある場合、1つのコマンドの動作をオーバーライドする唯一の方法は、Execute(String parameter)メソッド全体をコピーして、関心のある1つのcaseステートメントを変更することです。
  5. 静的分析ツールは、CommandParameterが単なる任意の文字列であるため、XAMLでのコマンドバインディングが間違っていることを通知できません。

文字列アプローチを使用したswitchステートメントの欠点は非常に強いため、既存のプロジェクトをnotにリファクタリングすることをお勧めします。

6
17 of 26

ここで考慮すべき重要な点は、ViewModelがない場合のViewだと思います。

すなわち。ビューには、さまざまなボタンなどのバインディングがあり、これらを区別する必要があります。

あなたの選択は次のようになります

NamedCommand(parameter)
GenericCommand(name, parameters)

パラメータが同じコマンドのパラメータではなくコマンド名になる場所はかなり明白だと思います。そのような場合は、NamedCommandを優先する必要があると思います。

ネーミングが難しいEdgeのケースがあるかもしれませんが、

1
Ewan

コマンドの背後にある全体的なアイデアは、それがビューに固有ではないということです。ビューのボタン、メニューオプション、右クリックコンテキストメニュー、または無数の他のUI要素から同じコマンドを実行することもできます。特定のコマンドクラスを作成することにより、単一の責任と再利用が可能になります。ビューモデルでコマンドの動作を定義することはお勧めしません。コードベース全体にコードをコピー/貼り付けするだけです。

1
RubberDuck