Contents
- The Background section formulates the problem.
- Then we look at the demo application.
- Then a "manual" command notification is described.
- This is followed by a generic but rather verbose, "naive" notification implementation.
- At last, the
DelegateWatchCommand
is presented that makes the code much better. If you have a little interest on general discussions and well known techniques, please jump directly to the section "DelegateWatchCommand".
- IN the end, some extensions (also supported by the library) and other usage cases are discussed.
Background
Several variations of DelegateCommand
for WPF and Silverlight are well known and used, I suppose, by all who follow the MVVM pattern. The interface ICommand
has only three members: Execute
, CanExecute
, and CanExecuteChanged
. With DelegateCommand
, it is easy to define Execute
and CanExecute
as delegates. If the value of CanExecute
depends on some properties that change, then each time they do, CanExecuteChanged
must be fired so that CanExecute
is evaluated anew. This change notification is not difficult to implement, but the straightforward way of doing this is firstly, boring and secondly, error prone.
Josh Smith has proposed in http://joshsmithonwpf.wordpress.com/2009/07/11/one-way-to-avoid-messy-propertychanged-event-handling/ to exploit the CommandManager
. I assume that many of us use his RelayCommand
. But this solution has still some drawbacks. The first one is that there is simply no CommandManager
in Silverlight and no one will prompt to check CanExecute
again. The second one is that the CommandManager
is aware only of the user input. If an essential property changes due to an async event (e.g., due to data delivered through WCF), the CommandManager
sleeps and can't awake your command.
Prism avoids using CommandManager (http://compositewpf.codeplex.com/Thread/View.aspx?ThreadId=226136) and the opinion of Karl Shifflett should be considered.
This article proposes another-way-to-avoid-messy-code when notifying a DelegateCommand
.
The basic assumption is that all objects involved in notification implement the INotifyPropertyChanged
interface (INotifyCollectionChanged
is also supported).
Demo Application
The demo application is very simple and only demonstrates the usage of the library compared with other implementations. Here is a snapshot:
The UI is rather unimpressive and WinForms like. The following diagram shows the classes behind the UI:
These objects are our sandbox where we can play with different commands. There is a root object of type MasterVM
that has a property named and typed Model
. The Model
object has a property named and typed SubModel
. An instance of MasterVM
is created when the demo program starts and is assigned to the DataContext
of the window.
The goal of the game is to write a command that increments the property Result
of the MasterVM
. It is allowed to increment the result only when a certain condition (specified below) holds. The commands must respect this condition in their CanExecute
. The condition depends on the properties of the Model
and SubModel
objects. Two string
and two int
properties that affect the condition are bound to TextBox
es and can be changed by the user. The boolean property ToggledProp
is also essential but doesn't depend on user input - it is toggled by a timer each second (the property is bound to a CheckBox
with the appropriate label but the CheckBox
is disabled).
Further, the rules of the game say that the object SubModel
doesn't exist permanently. The user can create or delete it with the button at the top of the window. Two properties that the condition depends on are located in the SubModel
. So, the commands that we are going to write must cope with the properties of dynamically created and nulled objects.
First, we will go to the sandbox corner that is surrounded by a blue border (in the demo app window and in the object diagram). Inside of the green border at the bottom of the window, older girls and boys play with Collections. We will get there near the end of the article.
Here is the condition that defines the "executability" of the commands:
Model.IntProp
must be greater than SubModel.AnotherInt
AND
Model.StringProp
must be longer than SubModel.AnotherString
AND
ToggledProp
must be true.
Different Kinds of Commands Bound to Different Buttons
All commands bound to the buttons in the blue border have the same Execute delegate:
_ => this.Result++
The CanAlwaysCommand
is unconditional. Its CanExecute
delegate is not set and this means that it is always true. The button "Unconditional" is bound to this command and is always enabled. This command violates the rules of the game and will never win. Obviously, this command needs no notifications of changed property values.
All other commands delegate their CanExecute
to the same CanIncrement()
method. Here is it:
private bool CanIncrement( object parameter ) {
return this.Model.SubModel != null
&& this.Model.IntProp > this.Model.SubModel.AnotherInt
&& this.Model.StringProp.Length > this.Model.SubModel.AnotherString.Length
&& this.Model.ToggledProp;
}
The Model
property is assigned in the constructor and never changes, so it is OK not to check this.Model
for not null.
RelayCommand
The button "Relay" refers to a RelayCommand
as it was described by Josh Smith in http://joshsmithonwpf.wordpress.com/2008/06/17/allowing-commandmanager-to-query-your-icommand-objects/ and has become a classic implementation. It hooks the CommandManager
's RequerySuggested
event and prompts the button to check CanExecute
anew each time the user clicks something somewhere, including changing the properties that are essential for the method CanIcnrement
. But the ToggledProp
property changes without user interaction and the "Relay" button can't react to its change. Its IsEnabled
property is calculated at the moment when you change something manually. Depending on the ToggledProp
value at this moment, the button's IsEnabled
is set to true or false and doesn't change as long as you don't click something again.
Classical DelegateCommand
The ManualCommand
is a simple DelegateCommand
that doesn't hook RequerySuggested
(like in Prism http://compositewpf.codeplex.com/releases/view/55580). Its method RaiseCanExecuteChanged()
must be called explicitly whenever an essential property changes. This needs a number of code lines (too many lines as for a simple and transparent "mission" of these lines), and the code is error prone since it depends on property names defined as strings. If a property is renamed, all occurrences of the string must be checked. If your property has a name that is heavily used in many classes (say, "Name" or "Parent"), you must carefully distinguish between the strings that must and must not be changed.
So, I don't suggest programming this way; we are simply going to see what should be done "manually", and later, we'll try doing the same, but in a better way.
Since CanIncrement
depends on properties of the Model
, we must hook the PropertyChanged
event of this.Model
in MasterVM
(in an absolutely standard way; you write this code every day and I list it here only to remind you how boring it is). Obviously, it would be not a good idea to notify the command directly from the setters of the Model
's properties - the Model
must not depend on the ViewModel
in any way, it must not contain any code that knows something about the ViewModel
. And even if we forget about MVVM, dispersing the notification code over nearly all objects has nothing to do with good design.
private Model _model;
public Model Model {
get { return _model; }
private set {
if( _model != value ) {
if( _model != null )
_model.PropertyChanged -=
new PropertyChangedEventHandler( _model_PropertyChanged
_model = value;
if( _model != null )
_model.PropertyChanged +=
new PropertyChangedEventHandler( _model_PropertyChanged );
this.AddSubmodelCommand.RaiseCanExecuteChanged();
}
}
}
Please note that RaiseCanExecuteChanged()
is called whenever the Model
changes, although CanIncrement()
doesn't depend explicitly on this.Model
. We need this, since if a new model instance is assigned, it has its own property values and CanIncrement()
must be re-evaluated. Here is the event handler:
void _model_PropertyChanged( object sender, PropertyChangedEventArgs e ) {
if( e.PropertyName == "IntProp" || e.PropertyName == "StringProp"
|| e.PropertyName == "ToggledProp" )
this.ManualCommand.RaiseCanExecuteChanged();
else if( e.PropertyName == "SubModel" )
this.SubmodelCopy = this.Model.SubModel;
}
The command is notified each time an essential property changes.
As you can see, the property SubModel
is handled differently. We must hook up its PropertyChanged
and handle it the same way as the Model
's event. We could do this directly in the same place where SubmodelCopy
gets its value:
void _model_PropertyChanged( object sender, PropertyChangedEventArgs e ) {
. . .
else if( e.PropertyName == "SubModel" )
if( this.Model.Submodel != null )
this.Model.Submodel.PropertyChanged +=
new PropertyChangedEventHandler( _submodel_PropertyChanged );
This code has one problem: we can hook the event, but we can't unhook it. At the moment the code is notified that this.Model.SubModel
is changed, the old value is already gone. So, we must have our own copy of SubModel
in the ViewModel
. This is the reason for creating an extra property SubmodelCopy
. The property looks exactly like the property Model
. It attaches/detaches an event handler that observes the essential properties of the current SubModel
instance and notifies the command. This property can be private - no one else but the notification code is interested in it.
Being equipped with this code, the ManualCommand
works properly. If you start the demo and click the "Create Submodel" button, the button "Manual" bound to the command will be enabled/disabled each second and respects all other values in CanIncrement
(the initial values of all properties in the demo program satisfy the CanIncrement
condition).
When we look at the code, we can see that to notify a command:
- we need a copy of each sub-object involved (being more precise: each object whose properties affect the
CanExecute
condition),
- we must hook/unhook
PropertyChanged
, and
- we must know the names of the properties.
So, let's try and write a program that makes this in a generic way.
NaiveCommand (an Attempt at Generic Notification)
To observe the result of an expression that looks like x.P1.P2. ... Pm
, we'll write a class that observes one property of one object (and call the class PropertyWatch
, the word "observer" is already heavily used), and we'll link as many instances as we need in a chain (PropertyWatchChain
class). Each "watch" in a chain (but the last one) supplies its successor with the object to be observed. The last object in a chain raises an event if its observed property changes. An attached event handler calls RaiseCanExecuteChanged()
of the command we want to notify. This is our plan for this section.
The essential properties and fields of the PropertyWatch
class are:
INotifyPropertyChanged Source { get; set; }
- the object to be observed;
string PropertyName{ get; }
- the name of the property to be observed;
Func<INotifyPropertyChanged, INotifyPropertyChanged> _getter;
- a delegate that extracts the value of the observed property (a private field set in the constructor);
IPropertyWatch Next { get; set; }
- the next element in the chain.
The last element in a chain is of type PropertyWatchTail
. It doesn't need the _getter
and Next
members, but it needs a pointer (called Parent
) to the PropertyWatchChain
it belongs to. Through this pointer, it can raise the event. Both classes PropertyWatch
and PropertyWatchTail
implement the IPropertyWatch
interface. The property Next
is typed to this interface and accepts any of these two classes.
For instance, in the demo program, commands must be notified when this.Model.SubModel.AnotherInt
changes. So, the objects should build the following structure:
The classes are simple, and there is nearly nothing that should be commented. Still, please note that all observed objects must implement INotifyPropertyChanged
. If a PropertyWatch
object gets a new value assigned to its Source
property, it must call the _getter
to obtain the value of the observed property and push the value to its successor. These assignments are denoted with the vertical lines in the picture. If the Source
property is set to null (so that there is nothing to observe and the getter can't be called), the object must still push null to its successor. If a PropertyWatchTail
instance gets a null as the object to observe, it must raise the event WatchedPropertyChanged
of PropertyWatchChain
.
So far so good. But if you look at the program that creates the "chains", you'll see how horrible it is (the function Cons()
in the snippet prepends an element to a chain):
private PropertyWatchChain w2;
private PropertyWatchChain w3;
private PropertyWatchChain w4;
private PropertyWatchChain w5;
private PropertyWatchChain w6;
private void BuildNaiveCommand() {
w2 = new PropertyWatchChain( new PropertyWatchTail( "IntProp" ) )
.Cons( new PropertyWatch( "Model", x => ((MasterVM)x).Model ) );
w2.Head.Source = this;
w2.WatchedPropertyChanged
+= new EventHandler<EventArgs>( w_WatchedPropertyChanged );
w3 = new PropertyWatchChain( new PropertyWatchTail( "AnotherInt" ) )
.Cons( new PropertyWatch( "SubModel", x => ((Model)x).SubModel ) )
.Cons( new PropertyWatch( "Model", x => ((MasterVM)x).Model ) );
w3.Head.Source = this;
w3.WatchedPropertyChanged +=
new EventHandler<EventArgs>( w_WatchedPropertyChanged );
w4 = new PropertyWatchChain( new PropertyWatchTail( "StringProp" ) )
.Cons( new PropertyWatch( "Model", x => ((MasterVM)x).Model ) );
w4.Head.Source = this;
w4.WatchedPropertyChanged
+= new EventHandler<EventArgs>( w_WatchedPropertyChanged );
w5 = new PropertyWatchChain( new PropertyWatchTail( "AnotherString" ) )
.Cons( new PropertyWatch( "SubModel", x => ((Model)x).SubModel ) )
.Cons( new PropertyWatch( "Model", x => ((MasterVM)x).Model ) );
w5.Head.Source = this;
w5.WatchedPropertyChanged
+= new EventHandler<EventArgs>( w_WatchedPropertyChanged );
w6 = new PropertyWatchChain( new PropertyWatchTail( "ToggledProp" ) )
.Cons( new PropertyWatch( "Model", x => ((MasterVM)x).Model ) );
w6.Head.Source = this;
w6.WatchedPropertyChanged
+= new EventHandler<EventArgs>( w_WatchedPropertyChanged );
}
void w_WatchedPropertyChanged( object sender, EventArgs e ) {
this.NaiveCommand.RaiseCanExecuteChanged();
}
The take away of the section about the NaiveCommand
is that:
- It is not difficult to implement a generic notification of commands;
- The definitions of what should be watched are concentrated in one place and not dispersed through the whole program;
- These definitions are not transparent, it's not possible to understand at a glance what properties of what objects are observed;
- The definitions are error prone since the property names are not checked by the compiler.
We can fix the last mentioned flaw if we use the following constructor:
public PropertyWatch(
Expression<Func<INotifyPropertyChanged, INotifyPropertyChanged>> getterExpr )
{
_propName = PropertySelectorUtils.GetPropertyName( getterExpr );
if( getterExpr == null )
throw new ArgumentNullException( "getterExpr" );
_getter = getterExpr.Compile();
}
But we'll better make two steps in this direction and define the whole chain of watchers with one lambda expression.
But first, a little discussion. The PropertyWatch
class treats all observed objects assigned to its Source
property as INotifyPropertyChanged
. Due to this simplification, all getters passed as the getterExpr
parameter must first cast their arguments. So, the getter for the first watcher in each chain is x => ((MasterVM)x).Model
. It is possible to write a generic typed version of PropertyWatch
that has two type arguments: T1
is the type of the observed object, and T2
is the type of the observed property and thus the type of the successor's observed object. For the last element in a chain, we need a generic type PropertyWatch
with only one type parameter. PropertyWatch<T1,T2>
inherits from PropertyWatch<T1>
. The type of Next
in PropertyWatch<T1,T2>
will be PropertyWatch<T2>
so that any PropertyWatch<T2,T3>
as an intermediate element or PropertyWatch<T2>
as the last chain element are acceptable as the successor's type. I don't believe that all these complications pay. Avoiding a pair of type casts per user interaction is not a reasonable goal, I suppose. But it is possible, possible. If you mind.
DelegateWatchCommand
This is a simple DelegateCommand
extended by a list of PropertyWatchChain
s that are built in the constructor out of lambda expressions. Well, there is nothing I can add to the description. Let us look at how a command instance is defined in the demo program.
private DelegateWatchCommand<MasterVM> _watchCommand;
public DelegateWatchCommand<MasterVM> WatchCommand {
get {
if( _watchCommand == null )
_watchCommand = new DelegateWatchCommand<MasterVM>(
_ => this.Result++, this.CanIncrement, this, x => x.Model.SubModel.AnotherString,
x => x.Model.SubModel.AnotherInt
x => x.Model.IntProp,
x => x.Model.StringProp,
x => x.Model.ToggledProp
);
return _watchCommand;
}
}
The real text differs a little from this snippet, since it (I mean the demo code ) uses/illustrates an extension described in the next section. Please note that the type parameter of the command's class is not the type of the command parameter as in some implementations of DelegateCommand
(more on the type parameter later).
As for me, this command looks much better. One glance is enough to see what properties its CanExecute
depends on. The lambda expressions are checked by the compiler. No messy code and the command is still notified of all essential changes including those implied by async events.
The class DelegateWatchCommand
inherits from DelegateCommand
that handles Execute
and CanExecute
delegates in a well-known way, and restricts the type parameter:
public class DelegateWatchCommand<T>: DelegateCommand
where T: class, INotifyPropertyChanged {
. . .
Let' take a look at the most interesting constructor and its helper method.
public DelegateWatchCommand( Action<object> execute, Func<object, bool> canExecute,
T source, params Expression<Func<T, object>>[] exprList )
: base( execute, canExecute )
{
_chains = exprList.Select( e => this.MakePropertyWatchChain( e ) ).ToList();
this.Source = source;
}
The helper method creates one chain out of one lambda expression and hooks its event.
private PropertyWatchChain MakePropertyWatchChain( Expression<Func<T, object>> expr ) {
var ret = PropertyWatchChain.FromLambda( expr );
ret.WatchedPropertyChanged
+= new EventHandler<EventArgs>( ret_WatchedPropertyChanged );
return ret;
}
Now a few words about the type parameter and the parameter "source
" in the constructor. The constructor assumes that all PropertyWatch
chains start with the same object instance, and this instance should be passed to the constructor as the third parameter or assigned later to the property Source
of the command. This restriction (only one root instance) seems to be feasible due to the following. The chains must lead to all essential and changeable properties that affect CanExecute()
of the command. If CanExecute()
manages somehow to access these values, then we can do this, also starting from the same point -- from the instance, where the CanExecute()
lives. So, the type parameter is the type, where CanExecute()
is implemented and the parameter "source
" is "this
" of the CanExecute()
, in most cases.
Alternatively, in the demo program, we could use this.Model
as the starting point. If you look at the lambda expressions, you will see that they all start with this.Model
. So we could use Model
as the type parameter and pass this.Model
as the third argument. The value can be null at the beginning (the watchers will be constructed but in a hibernated form -- they will never raise the event until something different than null is assigned). We must take care and assign this.Model
to the command's Source
property each time a new value is assigned to this.Model
. Actually, this means that we notify the command "manually" about the changes of the first object in all chains and let it observe the rest automatically, so a step back to a messy implementation. As noted previously in the demo program, the Model
is created in the constructor and never changes. So in this special case, starting chains with this.Model
could be reasonable.
If you follow the destiny of the lambda expressions in the DelegateWatchCommand
constructor, you will see that where the static method PropertyWatchChain.FromLambda()
is called, there is a kind of constructor of the PropertyWatchChain
class. The reason not to use a "real" constructor is that the PropertyWatchChain
class needs no type parameters while the FromLambda
does. The method uses the Visitor
class to handle the expressions. The Visitor
class follows (no wonder) the Visitor pattern. It must deal with a rather restricted sort of expressions. They consist solely of property accessors and end with a parameter. Type conversions may occur, but they are simply skipped (we have agreed to treat all types as INotifyPropertyChanged
). For the first property accessor, an instance of the PropertyWatchTail
class is created (a lambda expression tree reads from right to left). Each further property results in a PropertyWatch
instance that is prepended to the result chain when recursion in the Visitor
returns.
Extension One. Chains Joined to Trees
Often several property watch chains have a common beginning. This allows to save typing and to introduce some structure if we join (some) chains and represent them as a tree. Please note, lambda expressions used to build PropertyWatch
chains are never executed (as a whole). So we can insert additional "pseudo functions" that don't denote any meaningful computations and only give auxiliary information to the Visitor
.
So, we define an extension method:
public static object MultiWatch<T>( this T source,
params Expression<Func<T, object>>[] branches )
where T: class, INotifyPropertyChanged
{
throw new InvalidOperationException( "This method is not intended to be called" );
}
We can use the method this way:
_watchCommand = new DelegateWatchCommand<MasterVM>(
_ => this.Result++,
this.CanIncrement,
this,
x => x.Model.SubModel.MultiWatch(
y => y.AnotherString,
y => y.AnotherInt
),
x => x.Model.IntProp,
x => x.Model.StringProp,
x => x.Model.ToggledProp
);
Does it pay? It depends. If the common part is longer than in the demo, this feature can be useful.
The implementation behind it is as follows. The root chain that observes x.Model.SubModel
ends with an instance of a new class PropertyWatchMulti
instead of a PropertyWatchTail
. This class contains "continuation chains" and has two purposes:
- it pushes the observed object to all of the child chains and
- it listens to their
WatchedPropertyChanged
transferring the signal to its own PropertyWatchChain
instance.
Of course, the Visitor
class must be changed. If it finds a MethodCallExpression
and the method is MultiWatch
, it generates an instance of the PropertyWatchMulti
class and processes recursively each "continuation" expression.
Extension Two. Collections
Until now, we have handled only the classes that implement INotifyPropertyChanged
. There is another notification interface that is commonly used -- IObservableCollection
. It would be useful to support this interface too. For instance, a collection contains Point
s and a command must be executable if there is a point with a negative X value, or if all points have X greater than Y, or if all collection members are "valid", whatever does it mean in a specific program.
So we need a new class WatchCollection
. It observes membership changes and can watch one or more property paths in each collection element. This class is somehow similar to PropertyWatchMulti
because it has multiple successors (one for each collection element) and, maybe, multiple chains for each element. Here is the idea of how the class does its work. When an instance of the class is constructed, a "pattern" chain is created. It is then cloned for each new collection member. The property Source
is not copied by cloning because each copy gets its own source (the new collection element to be observed). If multiple chains must be watched in each element, the pattern starts with a nearly dummy chain that consists only of a PropertyWatchMulti
.
In a lambda expression, we will denote watching collection elements with another extension method that will never be called:
public static object CollectionWatch<T>( this ObservableCollection<T> source,
params Expression<Func<T, object>>[] branches )
{
throw new InvalidOperationException( "This method is not intended to be called" );
}
The first parameter is a lambda expression that starts in the root object and leads to the collection whose elements should be observed. The following parameters are lambda expressions that start in a collection element and end with the properties that should be observed.
The Visitor
is changed once more, of course. This change needs Reflection because the type parameter of the WatchCollection
instance that should be generated is not known statically.
Now let's return to the demo program. The controls at the bottom of the window illustrate a case of a command that must be enabled when a certain condition on the properties of collection elements holds. Let's look at the contents of the green border. The MasterVM
class has a property DemoCollection
of type ObservableCollection<DemoCollectionElement>
. The DemoCollectionElement
class has only one integer property X
and still must implement INotifyPropertyChanged
. The collection members are displayed in the ListBox
to the left. Two buttons above allow for:
- adding items with a random value of
X
in the range 0 to 10 and
- removing all elements.
The "Add Item" button allows to add not more than four items. So are the rules of the game.
And then the rules say that we must write a command that is enabled if the average of all X
s in the collection is greater than 9. The command property in the demo is called CollectionDependingCommand
and is bound to the button labeled "Depends on Average". The command must observe changes inside of the collection elements. The action of the command increments the field "Result" on the top of the window to produce some visible effect of clicking the button. The constructor and the CanExecute
of the command are listed below and illustrate the usage of CollectionWatch
:
public class MasterVM: NotifyPropertyChangedBase {
. . .
private DelegateWatchCommand<MasterVM> _collectionDependingCmd;
public ICommand CollectionDependingCommand {
get {
if( _collectionDependingCmd == null )
_collectionDependingCmd = new DelegateWatchCommand<MasterVM>(
_ => this.Result++,
this.IsAverageOK,
this,
x => x.DemoCollection.CollectionWatch( y => y.X ) );
return _collectionDependingCmd;
}
}
private bool IsAverageOK( object dummy ) {
if( this.DemoCollection.Count == 0 ) return false;
return this.DemoCollection.Average( x => x.X ) > 9;
}
The condition (average > 9) can hardly be satisfied with random numbers less than 10. But if you select an item in the list and edit its value in the TextBox
"Selected Item", the button can be enabled. This shows that the condition is evaluated anew if the X
property of any element changes. If you insert only one element and change its value to 10, the button will be enabled. Adding one more element will nearly always result in an average that is less than 9 and the button will be disabled. This shows that the command is aware of collection membership changes. Well, that is it.
Other Usages
The demo program illustrates another possible usage of the property chain observer. The PropertyWatchChain
class can be thought of as a quarter of a poor man's binding. It is a half, because it is OneWay, and it is a quarter, because it observes changes, but assigns nothing.
The class PropertyWatchTrigger
allows for triggering an action when a property change takes place. If this action assigns the changed value, you have something like a simple one way binding. Of course, the action can prescribe any computation, not necessarily an assignment. In the demo program, the field "Average" at the right hand side of the green border must be updated each time a member of the DemoCollection
changes its X
(or if a member is added or deleted). The following lines define the trigger that makes this job:
_triggerAverage = new PropertyWatchTrigger(
PropertyWatchChain.FromLambda<MasterVM>(
x => x.DemoCollection.CollectionWatch( y => y.X ) ), () => this.Average = this.DemoCollection.Count == 0
? 0.0
: this.DemoCollection.Average( e => e.X ), this );
The first argument defines the watch and the second argument defines the action. The third argument is the root of the observed property chain. The root object can be left null and assigned later.
Incorporating the ICommand Parameter Type
The implementation of the commands in the library completely ignores the ICommand
parameter simply passing it to the delegates. As you may see, the DelegateWatchCommand
inherits from the DelegateCommand
and cares only about notifications. It should be easy to implement in the same way as a version parameterized additionally with the ICommand
parameter type, that inherits from a Prism-like DelegateCommand
.
Practically
The demo program and the library are written in VS 2010 Express.
I suppose you can use the compiled DLL directly. The library and all classes are really small, so it may be better though to include sources in your library (where all your basic classes are located) and avoid one more DLL, one more reference, etc.
Points of Interest
Classes that notify commands of changes in property values are dynamically generated from lambda expressions.
Additional information needed to generate these classes in some special cases is represented by "pseudo functions" that are included in lambdas but are never called.
History
- Initial version: 07 March 2011.