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 建议的最终解决方案。请注意我如何为 RelayCommand 以及 Action 和 Predicate 使用通用的“对象”类型,因为这是我的方法参数(对象 myparameter)的类型:

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,如下所述:MVVM RelayCommand with parameters

旧不成功的尝试: 这是我到目前为止所拥有的:

                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

根据Josh Smith在MVVM 文章中发布的代码。您将使用 lambda 变量 param 来传递参数。在您的示例中,您根本没有使用“x”lambda 变量。这个变量应该是你 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));

由于您无法使用 Lamba 来构造命令,因此您的代码如下所示。

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 调用您的两个委托 (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 回答