[英]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<T>"/> 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<T>"/> 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.