2

パラメータを使用してRelayCommandのインスタンスを動的に作成しようとしています。

public class RelayCommand<T> : ICommand
{
    #region Declarations

    private readonly Predicate<T> _canExecute;
    private readonly Action<T> _execute;

    #endregion

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="RelayCommand&lt;T&gt;"/> class and the command can always be executed.
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    public RelayCommand(Action<T> execute)
        : this(execute, null)
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="RelayCommand&lt;T&gt;"/> class.
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    /// <param name="canExecute">The execution status logic.</param>
    public RelayCommand(Action<T> execute, Predicate<T> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");
        _execute = execute;
        _canExecute = canExecute;
    }

複数のメソッドを持つViewModelがありますが、今は次のようにリストします。

public void MyMethod(object parameter);
public bool CanMyMethod(object parameter);

次のように、それらをRelayCommandのインスタンスに動的にフックしたいと思います。

ICommand command = new RelayCommand<ViewModel>((x)=>myviewmodel.MyMethod(myparameter),(x)=> myviewmodel.CanExecuteMyMethod(myparameter));

前の行は機能しますが、メソッド名は実行時に渡されるため、同じことを動的に実現する必要があります。

編集:いくつかの説明:私のシナリオでは、名前でメソッドを直接参照することはできません。RelayCommandの作成に使用するメソッド名は文字列として渡されます。

解決:

これが@ZafarYousafiの提案を使用した私の最終的な解決策です。メソッドパラメータ(オブジェクトmyparameter)のタ​​イプであるため、RelayCommandおよびActionandPredicateにジェネリック'object'タイプを使用する方法に注意してください。

object myparameter = //Some value gets assigned here.
                Delegate td1 = null, td2 = null;
                MethodInfo method1 = myviewmodel.GetType().GetMethod("MyMethodNameAsString");

                if (tmethod1 != null)
                    td1 = Delegate.CreateDelegate(typeof(Action<object>), myviewmodel, method1);

                MethodInfo tmethod = viewmodel.GetType().GetMethod("Can" + "MyMethodNameAsString");
                if (method2 != null)
                    d2 = Delegate.CreateDelegate(typeof(Predicate<object>), myviewmodel, method2);

                if (d1 != null && d2 != null)
                {
                    item.Command = new RelayCommand<object>(obj => ((Action<object>) td1)(myparameter), obj => ((Predicate<object>)td2)(myparameter));
                }

これは次と同等である必要があります:

item.Command = new RelayCommand<object>(param=>myviewmodel.MyMethod(myparameter),param=>myviewmodel.CanMyMethod(myparameter));

重要な注意: @DanCが指摘したように、Josh Smithによって作成されたRelayCommandクラスは、作成時にパラメーターを受け取ることを目的としていません。適切に設計されたMVVMソリューションでは、RelayCommandパラメーターはCommandParameterプロパティのXAMLバインディングを介して渡されます。したがって、button.CommandがRelayCommandにバインドされている場合は、button.CommandParameterもバインドする必要があります。ここで説明するように:MVVMRelayCommandとパラメーター

古い失敗した試み: これは私がこれまでに持っているものです:

                Delegate d1 = null, d2 = null;
                MethodInfo method1 = myviewmodel.GetType().GetMethod("MyMethodNameAsString");
                if (method1 != null)
                    d1 = Delegate.CreateDelegate(typeof(Action<ViewModel>), myviewmodel, method1);

                MethodInfo method2 = myviewmodel.GetType().GetMethod("Can" + "MyMethodNameAsString");
                if (method2 != null)
                    d2 = Delegate.CreateDelegate(typeof(Predicate<ViewModel>), myviewmodel, method2);

                if (d1 != null && d2 != null)
                {
                    item.Command = new RelayCommand<ViewModel>((Action<ViewModel>)d1, (Predicate<ViewModel>)d2);
                }

これは正常に実行され、コンパイルエラーや実行時エラーは発生しませんが、RelayComandコンストラクターパラメーターを介してパラメーターを渡す方法がわかりません。

どんなアドバイスも大歓迎です、

ありがとう

私の前の質問に関連して

4

4 に答える 4

1

JoshSmithによるMVVMの記事に投稿されたコードによると。ラムダ変数paramを使用してパラメーターを渡します。あなたの例では、「x」ラムダ変数をまったく使用していません。この変数は、ExecuteメソッドとCanExecuteメソッドのパラメーターである必要があります。

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

コマンドがViewModel内に作成されていると仮定すると、次のように初期化されます。

ICommand command = new RelayCommand<MyParameterType>((myparameter)=>this.MyMethod(myparameter),(myparameter)=> this.CanExecuteMyMethod(myparameter));

ランバを使用してコマンドを作成することはできないため、コードは次のようになります。

Delegate d1 = null, d2 = null;
            MethodInfo method1 = myviewmodel.GetType().GetMethod("MyMethodNameAsString");
            if (method1 != null)
                d1 = Delegate.CreateDelegate(typeof(Action<YourParameterType>), myviewmodel, method1);

            MethodInfo method2 = myviewmodel.GetType().GetMethod("Can" + "MyMethodNameAsString");
            if (method2 != null)
                d2 = Delegate.CreateDelegate(typeof(Predicate<YourParameterType>), myviewmodel, method2);

            if (d1 != null && d2 != null)
            {
                item.Command = new RelayCommand<YourParameterType>((Action<YourParameterType>)d1, (Predicate<YourParameterType>)d2);
            }

これで、コマンドがMenuItemオブジェクト(この場合はICommandSource)に割り当てられた後、CommandParameterを使用して2つのデリゲート(d1、d2)が呼び出されます。

于 2012-06-21T16:57:56.850 に答える
0

インスタンスが構築されているサイトにRelayCommandは、のインスタンスのメソッドからデリゲートを渡すために必要なすべてのものがあるようですmyviemodel

item.command = new RelayCommand<ViewModel>(
    myviemodel.MyMethod, myviewmodel.CanExecuteMyMethod)

あなたが説明しているシナリオはおそらく仕事ですDelegate.DynamicInvokeが、あなたのスニペットにはその必要性は見られません...

于 2012-06-21T17:01:17.833 に答える
-1

次のようなコマンドを実行するには、RelayCommandクラスでメソッドを定義するだけです。

public void Execute(T model)
    {
        if(_canExecute(model))
            _execute(model);
    }
于 2012-06-21T16:56:51.890 に答える
-4

デリゲートをアクションにキャストするように入力しました。これで、パラメーターを渡す完全な自由が得られます。((Action<ViewModel>)d1)(yourparameter)

于 2012-06-21T16:59:38.353 に答える