Async ICommand implementation - c#

I'm facing a strange behavior by my asny ICommand implementation when I tried to disable the command while it's executing by default (even when no CanExecute predicate was passed to it).
public bool CanExecute(object parameter)
{
if (CanExecutePredicate == null)
{
return !mIsExecuting;
}
return !mIsExecuting && CanExecutePredicate(parameter);
}
public async void Execute(object parameter)
{
mIsExecuting = true;
await ExecuteAsync(parameter);
mIsExecuting = false;
}
I tried to introduce a private bool, which I set to true just before executing and to false afterwards. When execution is finished the bool is set, but CanExecute is only called after I click a mousebutton or move the mouse or w/e.
Now I tried to call
CanExecute(null);
after
mIsExecuting = false;
but that doesn't help neither. I dont know what I'm missing.
Thanks for your help
EDIT:
To clarify I add the constructors for this class aswell:
public AsyncRelayCommand(Func<object, Task> execute)
: this(execute, null)
{
}
public AsyncRelayCommand(Func<object, Task> asyncExecute,
Predicate<object> canExecutePredicate)
{
AsyncExecute = asyncExecute;
CanExecutePredicate = canExecutePredicate;
}
protected virtual async Task ExecuteAsync(object parameter)
{
await AsyncExecute(parameter);
}

In async scenarios, WPF tends not to know when to check CanExecute, that's why you have the "CanExecuteChanged" event in the Icommand interface.
You should have something like this in your command implementation:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
With the code above you can now do this:
public async void Execute(object parameter)
{
mIsExecuting = true;
RaiseCanExecuteChanged ( ); // Not necessary if Execute is not called locally
await ExecuteAsync(parameter);
mIsExecuting = false;
RaiseCanExecuteChanged ( );
}
This will tell WPF you want to refresh the CanExecute state of command.

Related

Can I extend the command class so that the button that binds to it is automatically disabled?

In my application I bound my buttons to commands with "MVVM".
My command is implemented as follows:
public Command CommandLoadStuff
{
get
{
return new Command(async () =>
{
await DoLongStuff();
});
}
}
The problem is that these commands are async and the user can click them multiple times causing the code to execute multiple times also.
As a first approach i used CanExecute:
public Command CommandLoadStuff
{
get
{
return new Command(async () =>
{
AppIsBusy = true;
await DoLongStuff();
AppIsBusy = false;
},() => !AppIsBusy);
}
}
Now I wonder if there isn't a better way than to handle the CanExecute for each command individually.
Since I initialize the command every time with "new" I wonder if the class "Command" could not be extended accordingly. It should block a second click of the button during the lifespan with CanExecute (Posibly in the Constructor?) and release it after the execution of the command is finished. ( Possibly in the Dispose function?)
Is there a way to achieve this?
Extending the class command this way is not possible, as far as I can tell, because Execute is non-virtual and you have to pass the execute action to the constructor. Anyway, there is still a way. Command derives from ICommand which has the following interface
public interface ICommand
{
event EventHandler CanExecuteChanged;
void Execute(object data);
bool CanExecute(object data);
}
You could create a class AsyncBlockingCommand (or whatsoever) that will return will return the respective value from CanExecute depending on whether an async method is still running (I know that there are issues with async void methods, so handle with care)
public class AsyncBlockingCommand : ICommand
{
bool _canExecute = true;
Func<Task> _toExecute;
public AsyncBlockingCommand(Func<Task> toExecute)
{
_toExecute = toExecute;
}
public event EventHandler CanExecuteChanged;
public async void Execute(object data)
{
_canExecute = false;
RaiseCanExecuteChanged();
await _toExecute();
_canExecute = true;
RaiseCanExecuteChanged();
}
public bool CanExecute(object data) => _canExecute;
private void RaiseCanExecuteChanged()
{
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
Before your async method is executed, _canExecute is set to false and CanExecuteChanged is raised. This way, your Button will get notified of CanExecute having changed and disable itself. Vice versa after the async method has been called. (Probably the RaiseCanExecuteChanged will have to be invoked on the main thread.)
You can use IsEnabled property to make the Button cannot be clicked.
Like following code.
<Button
Text="click"
Command={Binding Button1Command}
IsEnabled={Binding AreButtonsEnabled} />
If the value of IsEnabled is false, you can see this button, it is grey, if you click it, it will not execute any command.
Here is MyViewModel code.
private bool _areButtonsEnabled = true;
public bool AreButtonsEnabled
{
get => _areButtonsEnabled;
set
{
if (_areButtonsEnabled != value)
{
_areButtonsEnabled = value;
OnPropertyChanged(nameof(AreButtonsEnabled)); // assuming your view model implements INotifyPropertyChanged
}
}
}
public ICommand Button1Command { get; protected set; }
public MyViewModel()
{
Button1Command = new Command(HandleButton1Tapped);
}
private void HandleButton1Tapped()
{
// Run on the main thread, to make sure that it is getting/setting the proper value for AreButtonsEnabled
// And note that calls to Device.BeginInvokeOnMainThread are queued, therefore
// you can be assured that AreButtonsEnabled will be set to false by one button's command
// before the value of AreButtonsEnabled is checked by another button's command.
// (Assuming you don't change the value of AreButtonsEnabled on another thread)
Device.BeginInvokeOnMainThread(async() =>
{
if (AreButtonsEnabled)
{
AreButtonsEnabled = false;
// DoLongStuff code
await Task.Delay(2000);
AreButtonsEnabled = true;
}
});
}

How can I raise CanExecuteChanged() programmatically?

I need to programmatically raise CanExecuteChanged(). The ICommand class looks like this:
public class PlayCommand : ICommand
{
private readonly TpViewModel _tpViewModel;
private bool IsBusy;
public PlayCommand(TpViewModel tpViewModel)
{
_tpViewModel = tpViewModel;
}
public bool CanExecute(object parameter)
{
return !IsBusy;
}
public async void Execute(object parameter)
{
if (IsBusy)
return;
await Play();
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
private async Task Play()
{
IsBusy = true;
Console.WriteLine("Play")
IsBusy = false;
}
}
The Play button should be enabled as soon as the Play() method is completed. However, there seems to be a delay of a second or two before the button gets enabled.
I have tried CommandManager.InvalidateRequerySuggested() but it does not work.
You could use CommandManager.InvalidateRequerySuggested(), though this is fairly expensive. However, you can just extend your class with standard event patterns.
Note : This is only an example based on your code and not intended to be the worlds best-of-class ICommand implementation, modify it as you need
private EventHandler _canExecuteChanged;
public event EventHandler CanExecuteChanged
{
add
{
_canExecuteChanged += value;
CommandManager.RequerySuggested += value;
}
remove
{
_canExecuteChanged -= value;
CommandManager.RequerySuggested -= value;
}
}
public void RaiseCanExecuteChanged()
{
if (!IsBusy)
OnCanExecuteChanged();
}
protected virtual void OnCanExecuteChanged()
=> _canExecuteChanged?.Invoke(this, EventArgs.Empty);

The RelayCommand for enable/disable a button don't work like expected

The case is that I try to disable a button in the window form when it was clicked and after some time (some seconds) it should be enabled again.
But this didn't work. After a click on the button the command set the enabled to false and after some seconds the command set it back to true (I tested it, the order is right and it set it to true again) but the button is still not enabled on the window form.
For that case I use a RelayCommmand. The RelayCommand is a standard class you find on Internet and will be shown in the end.
To organise the command I wrote a class called Testclass:
class Testclass
{
private bool _testValueCanExecute;
public bool TestValueCanExecute
{
get { return _testValueCanExecute; }
set
{
_testValueCanExecute = value;
OnPropertyChanged();
}
}
public ICommand TestValueCommand { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public Testclass()
{
TestValueCommand = new RelayCommand(TestMethod, param => _testValueCanExecute);
TestValueCanExecute = true;
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private async void TestMethod(object obj)
{
TestValueCanExecute = false;
await Task.Delay(3000);
TestValueCanExecute = true;
}
}
In the XAML File I added a button as followed:
<Button x:Name="TestButton" Command="{Binding TestValueCommand}" Content="Test Button" HorizontalAlignment="Left" Margin="149,96,0,0" VerticalAlignment="Top" Width="75"/>
The MainWindow code looks as followed:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new Testclass();
}
}
So the RelayCommand use the TestMethod method set the command enable variable to false, wait 3 seconds and set them back to true. But as I wrote above the button on the window form still not enabled.
It would be nice to understand what happens here and how I can solve this.
Update:
I use the following Code for the RelayCommand:
public class RelayCommand : ICommand
{
private Action<object> execute;
private Func<object, bool> canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
}
The RelayCommand is a standard class you find on Internet ...
There is no such thing as a "standard class you find on Internet". In fact there are several different implementations of the RelayCommand available "on the Internet".
A good implementation should contain a method for raising the CanExecuteChanged event. MvvmLight's implementation has a RaiseCanExecuteChanged() method that does this. You need to call this one to "refresh" the status of the command:
private async void TestMethod(object obj)
{
RelayCommand cmd = TestValueCommand as RelayCommand;
TestValueCanExecute = false;
cmd.RaiseCanExecuteChanged();
await Task.Delay(3000);
TestValueCanExecute = true;
cmd.RaiseCanExecuteChanged();
}
The event is not raised automatically when you set the TestValueCanExecute property and raise the PropertyChanged event for the view model.
Edit: Your implementation doesn't have any RaiseCanExecuteChanged() method. Add one to your RelayCommand class and call it as per above:
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
I strongly recommend using existing frameworks, instead of inveting the wheel once again.
Take a look at ReactiveUI ReactiveCommand
In your case, it would do all the work by itself:
TestValueCommand = ReactiveCommand.CreateFromTask(async () => await Task.Delay(500));
You bind that command to a button in xaml and the button is disabled until command is done.
You can easily add another condition for disabling the command, and then, binding will disable button

redundant ICommand class for wpf mvvm

I'm still learning about wpf, however I'm familiar withe how to setup mvvm in wpf c#. However when it comes to the ICommand/RelayCommand stuff, its a bit of a confusing area for me. Over the past few months I've compiled a few implementations of the ICommand classes in order to create my tools. However I'm at the point now where I've read a few articles and I've looked at the code long enough, I'm looking for someone to help me out and put into simple terms what is going on here and if so, how can I combine/clean up these classes. At the moment the code seems redundant and I'm not sure how to go about optimizing it. Hope this isn't asking for to much. Thanks.
The two important things I want to maintain in this, is the ability to pass arguments to the commands as seen in this first usage example of RelayCommand. Secondly the ability to enable/disable a command as seen in the second command.
So in my tool i have this helper class.
1. I don't get the differences of use between the two classes inside this RelayCommand.cs. There is a public and an internal class.
2. Is there a need for both or can they be combine?
RelayCommand.cs
using System;
using System.Windows.Input;
namespace WpfApplication1.Helper
{
public class RelayCommand<T> : ICommand
{
private readonly Action<T> execute;
private readonly Predicate<T> canExecute;
public RelayCommand(Action<T> execute, Predicate<T> canExecute = null)
{
if (execute == null)
throw new ArgumentNullException("execute");
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (parameter == null)
{
return true;
}
else
{
return canExecute == null || canExecute((T)parameter);
}
}
public void Execute(object parameter)
{
execute((T)parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
// added
internal class RelayCommand : ICommand
{
private readonly Predicate<object> canExecute;
private readonly Action<object> execute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
if (execute == null)
throw new ArgumentNullException("execute");
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute == null || canExecute(parameter);
}
public void Execute(object parameter)
{
execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
}
An example of me using the RelayCommand.cs in my class object called Customer.cs
private ICommand addNewLicense_Command;
public ICommand AddNewLicense_Command
{
get
{
return addNewLicense_Command ?? (addNewLicense_Command = new RelayCommand<Customer>(n =>
{
AddNewLicense_Execute(n);
}));
}
}
So then in my MainViewModel.cs i have another ICommand Class in the same project my Helper class mentioned above is part of. Is this class necessary? It seems so similar to the RelayCommand class.
public class CommandHandler : ICommand
{
private Action _action;
private bool _canExecute;
public CommandHandler(Action action, bool canExecute)
{
_action = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action();
}
}
An example of me using CommandHandler in my MainViewModel.cs
private ICommand addNewUser_Command;
public ICommand AddNewUser_Command
{
get
{
return addNewUser_Command ?? (addNewUser_Command = new CommandHandler(() => AddNewUser_Execute(), true));
}
}
If you use a library like MVVM Lite then it will provide the RelayCommand implementations for you. Either way use the non-generic when you don't need a parameter passed in e.g. an "Ok" button:
public ICommand OkCommand { get { return new RelayCommand(Ok); } }
protected virtual void Ok()
{
// ... do something ...
}
The associated XAML is something like:
<Button Content="Ok" Command="{Binding OkCommand}" IsDefault="True" />
Use the generic when you want to pass a parameter:
public ICommand OpenClientCommand { get { return new RelayCommand<Client>(OnOpenClient); } }
private void OnOpenClient(Client client)
{
// ... do something with client ...
}
In this case you need to pass in a Client object via the command parameter:
<Button Content="Open" Command="{Binding OpenClientCommand}" CommandParameter="{Binding SelectedClient}"/>
Passing parameters is also handy when used with event triggers, e.g. you can add something like this to intercept your MainWindow's Closing event:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<cmd:EventToCommand Command="{Binding ClosingCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
This trigger passes the message arguments into your handler which gives you the opportunity to cancel it in the event that the user hasn't saved their changes:
public ICommand ClosingCommand { get { return new RelayCommand<CancelEventArgs>(OnClosing); } }
private void OnClosing(CancelEventArgs args)
{
if (!PromptUserForClose())
args.Cancel = true;
}
The RelayCommand you have is all you need. If you want to disable the command you can pass a method in the constructor do do so:
return addNewLicense_Command ?? (addNewLicense_Command = new RelayCommand<Customer>(n =>
{
AddNewLicense_Execute(n);
},AllowAddNeLicense));
...
bool AllowAddNewLicense()
{
return _allowAddEnabled;
}
The second class called CommandHandler is just another implementation of ICommand. The difference is that you can pass the "enabled" boolean inside the constructor, which means it will remain the same unless you create a new instance of it. While in the RelayCommand you can pass a function that gets executed everytime* so you can influence the outcome.

How to implement ICommand without parameters

In my project, i'd like to use MVVM (& Commands). I've started learning about commands and implementation of ICommand.
I'd like to create implementation of ICommand without parameters.
(To trigger loading of data/flushing of data etc. - I don't need any parameters to do it, so it just seems natural to try and create command without parameters)
This is the code I'm using:
using System.Windows.Input;
public class NoParameterCommand : ICommand
{
private Action executeDelegate = null;
private Func<bool> canExecuteDelegate = null;
public event EventHandler CanExecuteChanged = null;
public NoParameterCommand(Action execute)
{
executeDelegate = execute;
canExecuteDelegate = () => { return true; };
}
public NoParameterCommand(Action execute, Func<bool> canExecute)
{
executeDelegate = execute;
canExecuteDelegate = canExecute;
}
public bool CanExecute()
{
return canExecuteDelegate();
}
public void Execute()
{
if (executeDelegate != null)
{
executeDelegate();
}
}
}
But i got errors about not implementing the ICommand interface in the right manner
('XXX.YYYY.NoParameterCommand' does not implement interface member 'System.Windows.Input.ICommand.Execute(object)')
So I thought about doing it like this instead:
(Added the parameters that were missing from CanExecute and Execute)
public class NoParameterCommand : ICommand
{
...omitted - no changes here...
public bool CanExecute(object parameter) //here I added parameter
{
return canExecuteDelegate();
}
public void Execute(object parameter) //and here
{
if (executeDelegate != null)
{
executeDelegate();
}
}
}
IS THIS A GOOD WAY TO DO IT?
SHOULD I USE ANOTHER WAY? (IF SO, WHAT SHOULD I DO INSTEAD?)
This is a good way to do it.
No, you should not use another way.
Additional suggestions:
Thinking about this again, I would improve your architecture by introducing an additional hierarchy level where CanExecute() and Execute() are abstract. From that class, derive your command class that invokes delegates.
This way, you can decide later on whether you want to supply your logic for your parameterless commands via delegates or via subclassing your base command class.
I'm not really sure what your concern is. It is common to ignore the parameters in the ICommand interface.
If you really want CanExecute and Execute methods that don't have parameters, you can implement the interface explicitly (rather than implicitly). The ICommand methods will still exist, but to anyone looking at your object from the outside, they won't be able to see those methods:
bool ICommand.CanExecute(object parameter) { this.CanExecute(); }
public bool CanExecute()
{
//do work
}
You are essentially hiding the interface implemenation. If someone wants to directly call the CanExecute method from the interface, they would have to type cast to ICommand in order to do it. You really don't gain anything in doing it this way, but if you are concerned with how your class looks to outside developers (e.g. you are developing an API), then this can make it look a little cleaner as you are letting them know you do not require any parameters.
I personally prefer it this way:
public class MyCommand : ICommand
{
private static bool True() { return true; }
private readonly Action _execute;
private Func<bool> _canExecute;
private Func<bool> _isVisible;
public event EventHandler IsVisibleChanged;
public event EventHandler CanExecuteChanged;
public MyCommand(Action execute, Func<bool> canExecute = null, Func<bool> isVisible = null)
{
_execute = execute;
_canExecute = canExecute ?? True;
_isVisible = isVisible ?? True;
}
public void Execute()
{
_execute();
}
public Func<bool> CanExecute
{
set
{
_canExecute = value ?? True;
CanExecuteChanged(this, new EventArgs());
}
get { return _canExecute; }
}
public Func<bool> IsVisible
{
set
{
_isVisible = value ?? True;
IsVisibleChanged(this, new EventArgs());
}
get { return _isVisible; }
}
bool ICommand.CanExecute(object parameter)
{
return CanExecute();
}
void ICommand.Execute(object parameter)
{
Execute();
}
}
However, since the delegates usually don't change, I prefer an immutable version:
[ImmutableObject(true)]
public class MyImmutableCommand : ICommand
{
private static bool True() { return true; }
private readonly Action _execute;
private readonly Func<bool> _canExecute;
private readonly Func<bool> _isVisible;
[Obsolete("Will not be invoked, because the implementation never changes.")]
public event EventHandler CanExecuteChanged;
public MyImmutableCommand(Action execute, Func<bool> canExecute = null, Func<bool> isVisible = null)
{
_execute = execute;
_canExecute = canExecute ?? True;
_isVisible = isVisible ?? True;
}
public bool CanExecute()
{
return _canExecute();
}
public bool IsVisible()
{
return _isVisible();
}
public void Execute()
{
_execute();
}
bool ICommand.CanExecute(object parameter)
{
return CanExecute();
}
void ICommand.Execute(object parameter)
{
Execute();
}
}

Categories

Resources