19

MVVM を実行してコマンドを使用している場合、 MSDNの元の MVVM 記事の次の例のように、プライベート RelayCommand フィールドまたは DelegateCommand フィールドによってサポートされている ViewModel の ICommand プロパティがよく表示されます。

RelayCommand _saveCommand;
public ICommand SaveCommand
{
    get
    {
        if (_saveCommand == null)
        {
            _saveCommand = new RelayCommand(param => this.Save(),
                param => this.CanSave );
        }
        return _saveCommand;
    }
}

ただし、これは非常に煩雑で、新しいコマンドを設定するのはかなり面倒です (私は、このような入力をためらうベテランの WinForms 開発者と一緒に仕事をしています)。だから私はそれを単純化したいと思って、少し掘り下げました。get{} ブロックの最初の行にブレークポイントを設定すると、アプリが最初にロードされたときにのみヒットすることがわかりました。後で、必要な数のコマンドを起動できますが、このブレークポイントはヒットしません。これを単純化して、ViewModel から混乱を取り除きたいと考えていたところ、次のコードが同じように機能することに気付きました。

public ICommand SaveCommand
{
    get
    {
        return new RelayCommand(param => this.Save(), param => this.CanSave );
    }
}

ただし、C# やガベージ コレクターについては、これが問題を引き起こす可能性があるかどうか (場合によっては過剰なガベージが生成されるなど) を知るには十分ではありません。これは何か問題を引き起こしますか?

4

6 に答える 6

18

これは、ある定数値を計算する - たとえば整数の - プロパティを提供する場合とまったく同じです。get メソッドの呼び出しごとに計算するか、最初の呼び出しで作成してからキャッシュし、後の呼び出しでキャッシュされた値を返すことができます。そのため、getter が多くても 1 回呼び出された場合、まったく違いはありません。頻繁に呼び出された場合、パフォーマンスはいくらか (それほどではありません) 低下しますが、実際の問題は発生しません。

個人的には、MSDN 方式を次のように省略したいと思います。

RelayCommand _saveCommand;
public ICommand SaveCommand
{
  get
  {
    return _saveCommand ?? (_saveCommand = new RelayCommand(param => this.Save(),
                                                            param => this.CanSave ));
  }
}
于 2010-06-25T09:31:54.553 に答える
8

同じコマンドを呼び出す複数のコントロールがある場合は、MSDN の元の方法が必要であることがわかりました。それ以外の場合、各コントロールは独自の RelayCommand を新しく作成します。私のアプリにはコマンドごとに 1 つのコントロールしかないため、これに気づきませんでした。

そこで、ViewModel のコードを単純化するために、すべての RelayCommand を格納 (および遅延インスタンス化) するコマンド ラッパー クラスを作成し、それを ViewModelBase クラスにスローします。このようにして、ユーザーは RelayCommand または DelegateCommand オブジェクトを直接インスタンス化する必要がなく、それらについて何も知る必要がありません。

    /// <summary>
    /// Wrapper for command objects, created for convenience to simplify ViewModel code
    /// </summary>
    /// <author>Ben Schoepke</author>
    public class CommandWrapper
    {
    private readonly List<DelegateCommand<object>> _commands; // cache all commands as needed

    /// <summary>
    /// </summary>
    public CommandWrapper()
    {
        _commands = new List<DelegateCommand<object>>();
    }

    /// <summary>
    /// Returns the ICommand object that contains the given delegates
    /// </summary>
    /// <param name="executeMethod">Defines the method to be called when the command is invoked</param>
    /// <param name="canExecuteMethod">Defines the method that determines whether the command can execute in its current state.
    /// Pass null if the command should always be executed.</param>
    /// <returns>The ICommand object that contains the given delegates</returns>
    /// <author>Ben Schoepke</author>
    public ICommand GetCommand(Action<object> executeMethod, Predicate<object> canExecuteMethod)
    {
        // Search for command in list of commands
        var command = (_commands.Where(
                            cachedCommand => cachedCommand.ExecuteMethod.Equals(executeMethod) &&
                                             cachedCommand.CanExecuteMethod.Equals(canExecuteMethod)))
                                             .FirstOrDefault();

        // If command is found, return it
        if (command != null)
        {
            return command;
        }

        // If command is not found, add it to the list
        command = new DelegateCommand<object>(executeMethod, canExecuteMethod);
        _commands.Add(command);
        return command;
    }
}

このクラスも ViewModelBase クラスによって遅延インスタンス化されるため、コマンドを持たない ViewModel は余分な割り当てを回避します。

于 2010-06-24T17:24:38.033 に答える
7

私がしていることの1つは、VisualStudioに入力を任せることです。次のように入力してRelayCommandを作成できるコードスニペットを作成しました

rcタブ保存Enter

rcは、コードスニペットのショートカットタブで、入力したテキストを読み込み、他のすべての文言を作成します。

1つのコードスニペットを見て独自のコードスニペットを作成すると、二度と戻ることはありません:)

コードスニペットの作成の詳細については、http://msdn.microsoft.com/en-us/library/ms165394.aspxを参照してください。

于 2010-06-25T03:39:13.900 に答える
1

ただ書いてみませんか:

private readonly RelayCommand _saveCommand = new RelayCommand(param => this.Save(),
                param => this.CanSave );;

public ICommand SaveCommand { get { return _saveCommand; } }
于 2010-06-26T11:14:40.427 に答える
1

ビューモデルで ICommand プロパティを公開し、バッキング フィールドがない場合、このフィールドに一度だけバインドする限り、これは問題ありません。

CommandWrapper の GetCommand メソッドは、既に作成されている場合、コマンドを返します。

于 2012-04-04T12:19:41.263 に答える
0

ビューモデルで ICommand プロパティを公開し、バッキング フィールドがない場合、このフィールドに一度だけバインドする限り、これは問題ありません。基本的に、フォームが読み込まれて最初のバインドが実行されるとき、コマンドの get プロパティにアクセスするのはこのときだけです。

コマンドを 1 回だけバインドする場合はたくさんあります。

同じコマンドを複数のコントロールにバインドする場合は、バッキング フィールドが必要になります。

于 2011-03-29T16:34:08.547 に答える