Introduction
For quite some time, I’ve been using the common ActionCommand
implementation that can be found in almost every MVVM library. It works very well in MVVM world, but I didn’t really like all those “RaiseCanExecuteChanged
” calls scattered all around my ViewModel
s code. So I decided to turn things around and make the command responsible for tracking property changes. Hopefully, someone will find this useful.
TLDR: How Do I Use It?
Just instantiate it like a normal ActionCommand
, passing Execute
and CanExecute
callbacks. And register all properties that should be tracked. Do note that properties must be defined on an object implementing INotifyPropertyChange interface
.
private SelfEvaluatingActionCommand increaseCounter;
public ICommand IncreaseCounter
{
get
{
if (increaseCounter == null)
{
increaseCounter = new SelfEvaluatingActionCommand(OnIncreaseCounter, CanIncreaseCounter)
.AddPropertyTrigger(() => CounterMax)
.AddPropertyTrigger(() => Counter);
}
return increaseCounter;
}
}
And you are all set to go. Whenever CounterMax
or Counter
property changes, command will fire its CanExecuteChange
event.
Description and Extendibility
Have a look at the attached file which contains all necessary classes along with a basic sample project.
The core logic lies in PropertyTracker
class, which takes care of resolving property names provided via expression and hooking up to property change events of source objects. Internally, it builds a dictionary of source notification objects along with property names registered per given object. Whenever registered property changes, PropertyTracker
will invoke an action that was passed to it via constructor.
This way, you can hook up property tracking to your own commands without being restricted by existing inheritance chain. Of course, you can still subclass SelfEvaluatingActionCommand
if desired.
When implementing on your own set of commands via composition, be sure to implement ISelfEvaluatingCommand interface
. This will let you use those “Fluent” extension methods found in CommandExtensions
class.