6

私は現在、WPF と MVVM を学んでいます。ほとんどのこととそのしくみは理解できたと思いますが、RelayCommand (または DelegateCommand) の使用に関して理解できないものに遭遇しました。それは代表者の働き方に関係していると思います。

以下のコードはすべて、現時点ではテスト ソリューションにすぎないため、実際のコードではないことに注意してください。また、close などのパラメーターを必要としないコマンドについても、これが機能する理由を理解するためにこれを検討しています。

したがって、Josh Smith が作成した RelayCommand ( http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030 ) を使用すると、次のようなコマンドをセットアップできます。

RelayCommand updateTextContentCommand;

public ICommand UpdateTextContentCommand
{
    get
    {
        if (updateTextContentCommand == null)
        {
            updateTextContentCommand = new RelayCommand(
                param => this.UpdateTextContentCommand_Execute());
        }
        return updateTextContentCommand;
    }
}

この実行方法で:

public void UpdateTextContentCommand_Execute()
{
    this.TextContent = DateTime.Now.ToString();
}

TextBlock への単純なバインディングを使用して結果を確認し、コマンドをボタンにバインドしました。これはうまくいきます。私が得られないのは、ラムダ式を使用してコマンドを作成することです。パラメータAction<object>が必要ですよね?では、なぜこのコードが機能するのでしょうか。

上記のコードを次のように変更すると

if (updateTextContentCommand == null)
{
    updateTextContentCommand = new RelayCommand(
        this.UpdateTextContentCommand_Execute());
}

次のエラーが表示されます。

*「MVVM.RelayCommandTesting.Framework.RelayCommand.RelayCommand(System.Action)」に最適なオーバーロードされたメソッドの一致には、無効な引数がいくつかあります

引数 1: 'void' から 'System.Action' に変換できません*

()after Execute を削除すると、次のエラーが発生します。

引数 1: 'メソッド グループ' から 'System.Action' に変換できません

しかし、次のようにコードを変更すると:

if (updateTextContentCommand == null)
{
    updateTextContentCommand = new RelayCommand(
        this.UpdateTextContentCommand_Execute);
}

public void UpdateTextContentCommand_Execute(object param)
{
    this.TextContent = DateTime.Now.ToString();
}

それは準拠しており、正常に動作します。CommandParameter を使用するようにビューを変更すると、このメソッドを使用して param を使用してテキスト コンテンツを設定できますが、ラムダ スタイルを使用する場合は、パラメーターを行に渡す必要があるため、この param => のようになりますthis.UpdateTextContentCommand_Execute(param)

私のテストでは CommandParameter 値をハード コーディングしていますが、実際のシステムでは ViewModel のプロパティにデータ バインドされる可能性が最も高いと思われるため、パラメーターをラムダ スタイルで渡すことができます。

パラメーターなしのバージョンがラムダ スタイルで動作する理由を誰か説明できますか?

これを読んでくれてありがとう。

以下の質問にはラムダについてもいくつか質問があったようですが、それが私の質問に答えているようには見えません。

ViewModel で定義された RelayCommand を使用してパラメーターを渡す (Josh Smith の例から)

4

1 に答える 1

9

コンストラクター パラメーターは、次のシグネチャを持つデリゲートです。

void MethodName(T parameter)

ここで、パラメーターはタイプですT(RelayCommand の場合、これはタイプになりsystem.Objectます。

このコード:

param => this.UpdateTextContentCommand_Execute()

は、本質的に次のように展開されるラムダ式です。

void AnonymousMethod(object param)
{
    this.UpdateTextContentCommand_Execute();
}

したがって、この場合、パラメーター ( )渡しているのは、paramそれを使用していないだけです。これを理解すれば、他の例がそのように振る舞う理由を理解できるはずです。

例 1

if (updateTextContentCommand == null)
{
    updateTextContentCommand = new RelayCommand(
        this.UpdateTextContentCommand_Execute());
}

ここでは、void を返すメソッドを呼び出しています。Action<T>コンストラクターは、デリゲートに一致するものを期待しているため、エラーが発生します。

例 2

次に、次のようにブラケットを削除すると:

if (updateTextContentCommand == null)
{
    updateTextContentCommand = new RelayCommand(
        this.UpdateTextContentCommand_Execute);
}

これは、イベントへのサブスクライブに少し似ていると考えてください。

myObject.myevent += new Action<object>(this.UpdateTextContentCommand_Execute);

これは次のように短縮できます。

myObject.myevent += this.UpdateTextContentCommand_Execute;

したがって、コンストラクターは、デリゲートの署名と一致する署名を持つすべてのメソッドを受け入れます。Action<T>

void UpdateTextContentCommand_Execute(object parameter)

メソッドには次の署名があります。

void UpdateTextContentCommand_Execute()

ご覧のとおり、署名が一致しないため、コンパイラは文句を言います。

UpdateTextContentCommand_Executeオブジェクト パラメーターを受け入れるようにメソッドを更新すると、署名が一致するようになり、これが機能するようになりました。

于 2012-08-05T12:34:55.813 に答える