I'm trying to create an instance of a RelayCommand with parameters dynamically:
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;
}
I have a ViewModel with multiple methods, for now I'll just list:
public void MyMethod(object parameter);
public bool CanMyMethod(object parameter);
I want to hook them dynamically to an instance of RelayCommand as follows:
ICommand command = new RelayCommand<ViewModel>((x)=>myviewmodel.MyMethod(myparameter),(x)=> myviewmodel.CanExecuteMyMethod(myparameter));
The previous line works, however, my Method names are passed in at runtime so I need to achieve the same thing but dynamically.
EDIT: Just Some Clarification: In my scenario I CANNOT refer to my methods by name directly. The Method Name that I will use to create a RelayCommand WILL BE PASSED AS STRING.
SOLUTION:
Here is my final solution, using @ZafarYousafi suggestion. Notice how I use a generic 'object' type for my RelayCommand and for Action and Predicate since that is the type of my methods parameters (object 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));
}
Which should be equivalent to:
item.Command = new RelayCommand<object>(param=>myviewmodel.MyMethod(myparameter),param=>myviewmodel.CanMyMethod(myparameter));
IMPORTANT NOTE: As @DanC pointed out, the RelayCommand class created by Josh Smith is not intended to receive parameters at time of creation. In a well-architected MVVM Solution the RelayCommand parameter would be passed through XAML binding of CommandParameter property. So if you have a button.Command bound to a RelayCommand you also need to bind the button.CommandParameter as explained here: MVVM RelayCommand with parameters
OLD unsuccessful Attempt: This is what I have so far:
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);
}
That runs fine, no compilation or run-time errors, however I don't find how to pass my parameter through the RelayComand constructor parameters.
Any advice will be very appreciated,
Thanks
Related to my previous question