-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
Describe the problem this feature would solve
Command classes are marked as sealed. That makes it impossible to extend these classes with custom behavior.
The issue regarding WPF's CommandManager can be handled in different ways
a) Developers have to create completely new commands for WPF if they want to use CommandManager
b) Developers can extend existing Toolkit Commands to hook up CommandManager
c) Developers can add a NuGet Package called Microsoft.Toolkit.Mvvm.Input.Wpf to get the WPF specific commands if they want to continue to use WPF's CommandManager
In either case, unless there's a specific reason to mark the Command classes as sealed, I would mark them as unsealed, as this would allow not only option a) and c), but also b). And b) could also be a more elegant way for c) without the need to re-implement the whole thing.
So, this issue is a request to make the command classes open for extension.
Describe the solution
Remove the sealed keyword from the command classes in Microsoft.Toolkit.Mvvm.Input.
Also mark at least the CanExecuteChanged event in those command classes as virtual:
public virtual event EventHandler? CanExecuteChanged
Helpful, but not required, would be a property that says whether the Command can always be executed or not. Because only in the latter case, the CommandManager's RequerySuggested event needs to be attached.
Consider implementing this property in the Command classes:
public bool CanAlwaysExecute => canExecute is null;
Describe alternatives you've considered
Alternative to the changes is option a) for WPF developers to implement commands on their own, which means they don't get the commands from the Toolkit, which reduces the value of the Toolkit for them if they want to continue using WPF's CommandManager.
Additional context
With the changes applied, there could be a WPF-specific RelayCommand class like below (Just taking this command class as an example, the other three command classes can also be extended like this with the changes of this issue applied). And this class could be implemented by a developer itself (option b)) or we deliver a separate NuGet package that is WPF-specific. But first of all, the RelayCommand of the Toolkit and the other ICommand implementations should be open for extension to write the below code:
namespace Microsoft.Toolkit.Mvvm.Input.Wpf
{
public class RelayCommand : Microsoft.Toolkit.Mvvm.Input.RelayCommand
{
public RelayCommand(Action execute) : base(execute) { }
public RelayCommand(Action execute, Func<bool> canExecute) : base(execute, canExecute) { }
public override event EventHandler? CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
}
}
If even the additional CanAlwaysExecute property is added, the WPF-specific command could look like this:
namespace Microsoft.Toolkit.Mvvm.Input.Wpf
{
public class RelayCommand : Microsoft.Toolkit.Mvvm.Input.RelayCommand
{
public RelayCommand(Action execute) : base(execute) { }
public RelayCommand(Action execute, Func<bool> canExecute) : base(execute, canExecute) { }
public override event EventHandler? CanExecuteChanged
{
add
{
if(!CanAlwaysExecute)
{
CommandManager.RequerySuggested += value;
}
}
remove
{
if(!CanAlwaysExecute)
{
CommandManager.RequerySuggested -= value;
}
}
}
}
}