Call RelayCommand<T> with CanExecute Parameter - c#

How can I call a RelayCommand by passing in the CanExecute Parameter. The object is being bound as a command paramenter from the view. I have the following piece of code which says 'Delegate Func does not take 0 arguments'. Please help. The definition for OnPrintAllChartsInCurrentView and IsPrintAndExportEnabled is as follows.
RelayCommand m_PrintAllChartsCommand;
public ICommand PrintAllChartsCommand
{
get
{
return m_PrintAllChartsCommand ?? (m_PrintAllChartsCommand = new RelayCommand<object>(
OnPrintAllChartsInCurrentView,
() => IsPrintAndExportEnabled() //This line there is a compiler error
));
}
}
private void OnPrintAllChartsInCurrentView(object obj)
{
//do something. The obj is bound as command parameter from the view.
}
private bool IsPrintAndExportEnabled()
{
//I will do some operation here and change to return true or false later
return false;
}
Here is the RelayCommand class that I am trying to call
namespace GalaSoft.MvvmLight.Command
{
public class RelayCommand<T> : ICommand
{
//
// Summary:
// Initializes a new instance of the RelayCommand class that can always execute.
//
// Parameters:
// execute:
// The execution logic.
//
// Exceptions:
// T:System.ArgumentNullException:
// If the execute argument is null.
public RelayCommand(Action<T> execute);
//
// Summary:
// Initializes a new instance of the RelayCommand class.
//
// Parameters:
// execute:
// The execution logic.
//
// canExecute:
// The execution status logic.
//
// Exceptions:
// T:System.ArgumentNullException:
// If the execute argument is null.
public RelayCommand(Action<T> execute, Func<T, bool> canExecute);
//
// Summary:
// Occurs when changes occur that affect whether the command should execute.
public event EventHandler CanExecuteChanged;
//
// Summary:
// Defines the method that determines whether the command can execute in its current
// state.
//
// Parameters:
// parameter:
// Data used by the command. If the command does not require data to be passed,
// this object can be set to a null reference
//
// Returns:
// true if this command can be executed; otherwise, false.
public bool CanExecute(object parameter);
//
// Summary:
// Defines the method to be called when the command is invoked.
//
// Parameters:
// parameter:
// Data used by the command. If the command does not require data to be passed,
// this object can be set to a null reference
public virtual void Execute(object parameter);
//
// Summary:
// Raises the GalaSoft.MvvmLight.Command.RelayCommand`1.CanExecuteChanged event.
public void RaiseCanExecuteChanged();
}
}

If you are taking a command parameter of type T (which you are declaring as object), the RelayCommand CanExecute requires a single argument of type T and returns bool. You are passing in an anonymous function which takes no arguments and returns a bool. You can simply replace
() => IsPrintAndExportEnabled();
with
arg => { return IsPrintAndExportEnabled(); }
if you do not intend to do anything with the object passed to the CanExecute.
If you do not need a command parameter, then you do not need to declare your RelayCommand as
RealyCommand<object>(execute, canExecute);
it can simply be
RelayCommand(execute, canExecute);
where in this case the Execute would take no arguments and return void and the CanExecute would take no arguments and return a bool.

It should be like this. Notice that RelayCommand canExecute parameter is Func<T,bool> it means that you pass method with the same signature (like below). For more information about Func<T,TResult> see this.
RelayCommand m_PrintAllChartsCommand;
public ICommand PrintAllChartsCommand
{
get
{
return m_PrintAllChartsCommand ?? (m_PrintAllChartsCommand = new RelayCommand<object>(
OnPrintAllChartsInCurrentView,
IsPrintAndExportEnabled
));
}
}
private void OnPrintAllChartsInCurrentView(object arg)
{
}
private bool IsPrintAndExportEnabled(object arg)
{
return false;
}

This is what works for me (IsRealShunter is a boolean property):
RaiseAlarmClickCommand = new RelayCommand<Guid>(RaiseAlarmClick, x => IsRealShunter);
RaiseAlarmClick is a method:
private void RaiseAlarmClick(Guid idPrinter) {...}
One small note, if something gets updated in your view model and you want to make sure your RelayCommand reflects the changes, call this from where the change occured:
RaiseAlarmClickCommand.RaiseCanExecuteChanged();

This is what worked for me. In case if it helps anyone. First look at the RelayCommand, the way I am declaring is wrong. It should be RelayCommand<object> This is the complete declaration and usage.
RelayCommand<object> m_PrintAllChartsCommand;
public ICommand PrintAllChartsCommand
{
get
{
return m_PrintAllChartsCommand ?? (m_PrintAllChartsCommand = new RelayCommand<object>(
OnPrintAllChartsInCurrentView, IsPrintAndExportEnabled));
}
}
private void OnPrintAllChartsInCurrentView(object arg)
{
}
private bool IsPrintAndExportEnabled(object arg)
{
}

Related

Is a command a sort of event handler or why does my button execute the command?

I'm learning about wpf, delegates, event and I have some clue on what does what, but I'm a little lost when it comes to implementing ICommand
I have a class the implements the ICommand interface like this
class RelayCommand : ICommand
{
private Action<object> _execute;
private Func<object, bool> _canExecute;
public RelayCommand(Action<object> execute) : this (execute, null)
{
}
public RelayCommand(Action<object> execute, Func<object,bool> canExecute)
{
this._execute = execute;
this._canExecute = canExecute;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
//throw new NotImplementedException();
return true;
}
public void Execute(object parameter)
{
//throw new NotImplementedException();
this._execute(parameter);
}
public void OnCanExecute()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
And then my ViewModel that uses i.
class PersonViewModel
{
public ICommand ICommandPresenter { get; set; }
public PersonModel PM;
private string _btnString = "";
#region Propertys
public string ButtonString
{
get {return _btnString; }
set
{
if (_btnString.Equals(value))
{
return;
}
_btnString = value;
}
}
public string Name { get { return PM.Name; } set
{
PM.Name = value;
}
}
#endregion Propertys
public PersonViewModel()
{
PM = new PersonModel();
ICommandPresenter = new RelayCommand(ChangeName);
}
public void ChangeName(object a)
{
string s = a as string;
MessageBox.Show("Hello from PersonViewModel Commander: " + s);
}
}
This is where it gets confusing for me. In the RelayCommand class I have an event CanExecuteChanged but that event is never executed/fired. From what I've understood from my reading on events is that you don't "need" to have subscribers to an event, but if you're going to have an event you should atleast have somewhere in the code that executes it. But I don't have that in my code but for some reason my button still does what I command it to do. I still understand that I've clicked the button but I don't have anything in my code that is subscribed to that button.
Why is my button able to execute my code even though I don't have an event connected to it?
Since I don't have any subscribers connected to CanExecuteChanged event does it becomes useless?
Is the command acting like an event? if so, please describe the whole process from clicking the button to executing the command.
CanExecuteChanged is member of ICommand class and, simplifying the things, is used by wpf framework to enable/disable your button depending on result of CanExecute() method. CanExecute is not tight to the code you want to execute when you click the button, but to the condition, when it's legal to be done.
Command executes your code, because you send pointer to your method(ChangeName method) here:
ICommandPresenter = new RelayCommand(ChangeName);
So you are not using CanExecuteChange at all, because you are invoking this constructor:
public RelayCommand(Action<object> execute).
To have CanExecute you have to invoke overloaded constructor that accepts CanExecute predicate:
public RelayCommand(Action<object> execute, Func<object,bool> canExecute)
And to invoke it just pass some function that returns a bool as second parameter:
ICommandPresenter = new RelayCommand(ChangeName, ()=>MyCustomLogicWhenButtonIsActive());
Based on what I saw in .Net's source code, the command assigned to the button's Command property is executed in the following way:
Clicking the button calls the button's OnClick() method (located in the button's ButtonBase base class).
The OnClick() method (see source here) calls the Commands.CommandHelpers.ExecuteCommandSource() method, passing this as the command source parameter.
The ExecuteCommandSource() (see source here) further calls the CriticalExecuteCommandSource() method, passing the same command source as a parameter.
Finally, the CriticalExecuteCommandSource() method (see source here) accesses the command source's Command member, and:
checks if the command's CanExecute() method returns true,
if it's true, it calls the command's Execute() method.
(If you use a RelayCommand implementation, then obviously, the RelayCommand class relays the call to the specific method you passed to its constructor when you instantiated it.)
So, to answer your question whether commands are fired through an event:
The source indicates that the OnClick() method executes the command directly, not through event handling. As you can see in the source, this method does raise the Click event, but it does so separately from the command execution.
Though, it remains unanswered how the OnClick() method is being called in the first place by the framework; I have no idea about that.

Activator.CreateInstance and passing a boxed object to an invoked method

I have the following code ...
My Command handler:
public class MyHandler : IHandler
{
// I Want to get rid of this method
public override void ExecuteOperation(BaseOperation operation)
{
// This is a work-around
this.ExecuteOperation(operation as SpecificOperation);
}
public override void ExecuteOperation(SpecificOperation operation)
{
// Do actual work here
}
}
My Command handler dispatcher:
private dynamic FindOperationHandler(TBaseProvisioningOperation operation)
{
... some logic here
return Activator.CreateInstance(handlerType, ... args here ...)
}
My consumer code
public void PerformProvisioningOperation(BaseOperation operation)
{
// Find the correct handler for this operation
var operationHandler = this.FindOperationHandler(operation as TBaseProvisioningOperation);
// make it execute the operation
// NOTE: 'operation' is SpecificOperation type, for example
operationHandler.ExecuteOperation(operation); // <--- problem is here
}
The issue is that when I create an instance of my handler class with the Activator.CreateInstance and pass it a boxed object (i.e. as "BaseOperation") parameter, .NET looks for a method in the handler, which has a parameter of the base type, instead of automatically invoking the one which can handle the object if it were unboxed (i.e. explicitly cast).
Of course we have SpecificOperation : BaseOperation
In other words: I want when I execute operationHandler.ExecuteOperation(operation);, .NET to invoke ExecuteOperation(SpecificOperation operation) instead of ExecuteOperation(BaseOperation operation), because the operation parameter is boxed (i.e. it IS SpecificOperation but is downcast-ed as BaseOperation).
How do I achieve that?
Edit:
public interface IHandler<TOperation> where TOperation : BaseOperation
{
/// <summary>
/// TODO: Get rid of this method
/// </summary>
/// <param name="operation">The operation to execute - boxed</param>
void ExecuteOperation(BaseOperation operation);
/// <summary>
/// Executes the operation
/// </summary>
/// <param name="operation">The operation to execute - unboxed</param>
void ExecuteOperation(TOperation operation);
}
Assuming you're using dynamic here to achieve Double-Dispatch, the problem is that you're casting the wrong object.
It's the operation variable that needs to be casted (in order to defer overload resolution until runtime), not the operationHandler.
Try this instead:
operationHandler.ExecuteOperation(operation as dynamic);
And you can avoid the redundant dynamic definition on your FindOperationHandler:
private IHandler FindOperationHandler(TBaseProvisioningOperation operation)
{
return Activator.CreateInstance(handlerType, ... args here ...) as IHandler;
}
See Double-Dispatch
You should avoid returning dynamic if the complete code is in C#. The Activator.CreateInstance is returning an Object not a dynamic.
Dynamics are for interop between scriptlanguages when the properties/methods aren't strongtyped.
Too bad you didn't described the IHandler interface, but...
I think; The problem you facing is your interface defines that your class must implement the void ExecuteOperation(BaseOperation operation); This way your FindOperationHandler should return an IHandler.
private IHandler FindOperationHandler(TBaseProvisioningOperation operation)
{
... some logic here
return (IHandler)Activator.CreateInstance(handlerType, ... args here ...)
}
And for your handler:
public class MyHandler : IHandler
{
public override void ExecuteOperation(BaseOperation operation)
{
var operation = (SpecificOperation)operation;
// Do actual work here
}
}

Passing an Action with Different Parameters

I have a class in C# named Button and I want the Button have a functionality that can be passed through its constructor and whenever the Button was pressed the Action executes.
Button(Rect rect, string text, Action Func);
I have used Action and It worked perfectly until I found out that I can't pass a void Action with arguments.
For example:
void DoSomething(string str);
How can I be able to pass any void Action with any arguments?
The button doesn't have to care about the argument, but it still needs to be passed a delegate with no arguments and returning void. This is easily done:
new Button(rect, text, () => YourMethod(whateverArgument))
Depending on what you're trying to do, whateverArgument can be a local, a constant or a field. Just think about when it's supposed to read the value to pass to the inner method.
Sure you can pass arguments, just use the following:
Button b = new Button(.., .., () => DoSomething("YourString");
I advice you to use simplefied command pattern:
Create base class or interface Command
interface ICommand
{
void Execute();
}
//Create secific command and pass parameters in constructor:
class Command : ICommand
{
public Command(string str)
{
//do smth
}
void Execute()
{
//do smth
}
}
Button(Rect rect, string text, ICommand cmd)
{
cmd.Execute();
}

What is my mistake in implementing an asynchronous RelayCommand?

I am learning WPF and MVVM at the moment and I faced a problem when i tried to write unit tests for a viewmodel, whose commands invoke async methods. That problem is well-described in this question. That question also has a solution: to write a new Command class with an additional awaitable method that can be awaited in unit tests. But since i use MvvmLight, i decided not to write a new class, but to inherit from the built-in RelayCommand class instead. However, i don't seem to understand how to do it properly. Below is a simplified example that illustrates my problem:
AsyncRelayCommand:
public class AsyncRelayCommand : RelayCommand
{
private readonly Func<Task> _asyncExecute;
public AsyncRelayCommand(Func<Task> asyncExecute)
: base(() => asyncExecute())
{
_asyncExecute = asyncExecute;
}
public AsyncRelayCommand(Func<Task> asyncExecute, Action execute)
: base(execute)
{
_asyncExecute = asyncExecute;
}
public Task ExecuteAsync()
{
return _asyncExecute();
}
//Overriding Execute like this fixes my problem, but the question remains unanswered.
//public override void Execute(object parameter)
//{
// _asyncExecute();
//}
}
My ViewModel (based on the default MvvmLight MainViewModel):
public class MainViewModel : ViewModelBase
{
private string _welcomeTitle = "Welcome!";
public string WelcomeTitle
{
get
{
return _welcomeTitle;
}
set
{
_welcomeTitle = value;
RaisePropertyChanged("WelcomeTitle");
}
}
public AsyncRelayCommand Command { get; private set; }
public MainViewModel(IDataService dataService)
{
Command = new AsyncRelayCommand(CommandExecute); //First variant
Command = new AsyncRelayCommand(CommandExecute, () => CommandExecute()); //Second variant
}
private async Task CommandExecute()
{
WelcomeTitle = "Command in progress";
await Task.Delay(1500);
WelcomeTitle = "Command completed";
}
}
As far as i understand it, both First and Second variants should invoke different constructors, but lead to the same result. However, only the second variant works the way i expect it to. The first one behaves strangely, for example, if i press the button, that is binded to Command once, it works ok, but if i try to press it a second time a few seconds later, it simply does nothing.
My understanding of async and await is far from complete. Please explain me why the two variants of instantiating the Command property behave so differently.
P.S.: this behavior is noticeable only when i inherit from RelayCommand. A newly created class that implements ICommand and has the same two constructors works as expected.
OK, I think I found the problem. RelayCommand uses a WeakAction to allow the owner (target) of the Action to be garbage collected. I'm not sure why they made this design decision.
So, in the working example where the () => CommandExecute() is in the view model constructor, the compiler is generating a private method on your constructor that looks like this:
[CompilerGenerated]
private void <.ctor>b__0()
{
this.CommandExecute();
}
Which works fine because the view model is not eligible for garbage collection.
However, in the odd-behavior example where the () => asyncExecute() is in the constructor, the lambda closes over the asyncExecute variable, causing a separate type to be created for that closure:
[CompilerGenerated]
private sealed class <>c__DisplayClass2
{
public Func<Task> asyncExecute;
public void <.ctor>b__0()
{
this.asyncExecute();
}
}
This time, the actual target of the Action is an instance of <>c__DisplayClass2, which is never saved anywhere. Since WeakAction only saves a weak reference, the instance of that type is eligible for garbage collection, and that's why it stops working.
If this analysis is correct, then you should always either pass a local method to RelayCommand (i.e., do not create lambda closures), or capture a (strong) reference to the resulting Action yourself:
private readonly Func<Task> _asyncExecute;
private readonly Action _execute;
public AsyncRelayCommand(Func<Task> asyncExecute)
: this(asyncExecute, () => asyncExecute())
{
}
private AsyncRelayCommand(Func<Task> asyncExecute, Action execute)
: base(execute)
{
_asyncExecute = asyncExecute;
_execute = execute;
}
Note that this actually has nothing to do with async; it's purely a question of lambda closures. I suspect it's the same underlying issue as this one regarding lambda closures with Messenger.

Using methods as a default parameter

I'm looking to create a Button class in my custom XNA GUI that accepts methods as an argument, similar to how, in Python's tkinter you can just set the function to be called with Button.config(command = a_method) .
I've read about using delegates as parameters here, here and here, but I don't seem to be any closer to getting it working. I don't fully understand how delegates work, but I've tried several different things unsuccessfully, like using Func<int>? command = null in order to test later to see if command is null then I'd call the preset default, but then I get a Func cannot be nullable type or something similar.
Ideally the code'd be something like:
class Button
{
//Don't know what to put instead of Func
Func command;
// accepts an argument that will be stored for an OnClick event
public Button(Action command = DefaultMethod)
{
if (command != DefaultMethod)
{
this.command = command;
}
}
}
But it seems like everything I've tried is not working out.
Default parameters must be a compile time constant. In C#, Delegates can't be constants. You can achieve a similar result by providing your own default in the implementation. (just using Winforms here)
private void button1_Click(object sender, EventArgs e)
{
Button(new Action(Print));
Button();
}
public void Button(Action command = null)
{
if (command == null)
{
command = DefaultMethod;
}
command.Invoke();
}
private void DefaultMethod()
{
MessageBox.Show("default");
}
private void Print()
{
MessageBox.Show("printed");
}
The error you got about Func<T> not being nullable it right - it is a reference type and only value types can be nullable.
To default a Func<T> parameter to null, you can simply write:
Func<int> command = null
If you are interested in a default value, would something like this work?
class Button
{
//Don't know what to put instead of Func
private readonly Func defaultMethod = ""?
Func command;
// accepts an argument that will be stored for an OnClick event
public Button(Action command)
{
if (command != defaultMethod)
{
this.command = command;
}
}
}

Categories

Resources