簡體   English   中英

如何使用參數從lambda表達式創建委托?

[英]How to create delegate from lambda expression with parameters?

我正在嘗試動態創建帶參數的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和參數

不成功的嘗試:這是我到目前為止的事情:

                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構造函數參數傳遞參數。

任何建議將不勝感激,

謝謝

與我之前的問題有關

根據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)。

似乎在構造RelayCommand實例的站點上,您已經具有從myviemodel實例方法傳遞委托所需的一切。

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

您所描述的場景可能是Delegate.DynamicInvoke的工作,但您的代碼段中沒有此需求...

只需在RelayCommand類上定義一個方法即可執行以下命令:

public void Execute(T model)
    {
        if(_canExecute(model))
            _execute(model);
    }

您已經鍵入了將委托轉換為行動的((Action<ViewModel>)d1)(yourparameter) ,現在您可以完全自由地傳遞參數((Action<ViewModel>)d1)(yourparameter)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM