… standard events like MouseDown, KeyUp.
P682 [[wpf recipes]] presented a surprisingly brief yet complete solution. The sample code takes fewer than 10 lines of xaml and c#,
but it's good to point out the salient features —
– no command, just routed events
– this technique requires a containment hierarchy, which exists in every WPF window
– If you want to suppress an event within a container, then apply the trick at that container level
– Trick is on the Preview tunneling event
–IV + proj
dprop (dependency property), aprop (attached property)?
logical ^ visual tree
containers – details
event handling – deeper
various common controls
bind to a method
templates – succinctly
resource dictionary? succinctly
observable collection? pro
alternatives to mvvm? pro
threading problems in wpf? pro
In most of my projects, my commands inevitably need access to the VM. The Execute() and CanExecute() all need to access the VM. (See
other posts why VM is one of the top 3 players in a command set-up.)
Q: how does the command methods get a handle on the VMs? I know more than 1 technique.
A: [[wpf succinctly]] shows that in xaml, we can pass the VM as CommandParameter into the Execute() method
A: ctor injection — VM is constructor-injected in the command instance.
In a way, the command objects and VM objects are inter-dependent.
0) The VM often exposes the command as a CLR property, to be accessed by the xaml “Hollywood”
1) The command methods directly uses the VM object.
To reduce coupling, perhaps we can introduce interfaces. Necessary?
This is a revisit to the “BB” in the post on two “unrelated” categories of delegate —
BB) event field Backed by a multicast delegate instance
If a class defines 2 events (let’s assume non-static), we can think of them as 2 newsletter titles both owned by each class Instance. Say Xbox newsletter has 33 subscribers, and WeightWatcher newsletter has 11 subscribers. If we have 10 classes instances, theen 440 subscriptions.
In general, Each newsletter title (i.e. event field) has
* exactly 1 owner/broadcaster i.e. the class instance
* 0 or more subscribers, each a 2-pointer wrapper, as described in other posts on delegates.
You can say each newsletter title (i.e. each event field) defines a M:1 relationship.
Forgive me for repeating the obvious — don’t confuse an event Field vs an event Firing. The Xbox newsletter can have 12 issues (12 event firings) a year, but it’s all under one newsletter title.
In my project a view model’s method VM.RepaintColors() needs to modify a View object DataGrid.
By basic OO principle, we know views “depend” on ViewModels, so ViewModels should not depend on (or directly edit the properties of) Views. When a data change needs to bubble up to view, we use the event infrastructure to notify the binding system to re-query the ViewModel objects.
Therefore my design above was a violation – VM.RepaintColors() directly manipulates DataGrid. I eventually solved the problem using event notification. RepaintColors() was moved into MainPage.xaml.cs i.e. the code behind class (I know this is anti-MVVM but still an improvement). As part of the view, CodeBehind (CB) class has full access to all ViewModel objects and View objects. Therefore if the original VM. RepaintColors() implementation need any field of the VM object, it still has access.
Remember the VM used to call this.RepaintColors() inside its various methods. Now with this change, it must fire the event RepaintColorsNeeded. This would notify the listening CodeBehind and trigger CB. RepaintColors() method. The hook-up is by event registration —
Right after the CodeBehind instantiates the VM, it registers CB. RepaintColors() with the VM’s RepaintColorsNeeded event.
Note despite the notation in this write-up, RepaintColor() is always a non-static method, and uses the non-static fields.
My conclusion — many constructs in this space have limited practical value — CV base type, CVS.
http://www.zagstudio.com/blog/466 is an authoritative comparison.
* CVS (not CV) can be constructed in xaml.
* CV and CVS can both be used in c# cod, but i feel almost *always* we only use a subtype of CV.
CVS is designed to support __simple__ custom sorting/filtering etc directly in xaml. First You inject the collection into your CVS instance, then secondly you retrieve the view from CVS and inject the view into the visual (items control). A CVS instance is a wrapper over 2 objects
– The physical collection (often an ObservableCollection)
– A CV (or subtype) object
I guess a CV baseclass instance isn’t terribly useful if you want any customization — see below. Instead, you either use a CVS or a CV subclass instance
– For __simple__ sorting, use cvs in xaml
– For sophisticated sorting that demands c# coding, cast the CV to one of the 2 subclasses. This is the standard and natural choice.
http://www.zagstudio.com/blog/441 seems to agree with my guess.
As other authors pointed out, we should and could avoid using a view that’s a CollectionView base type — poor performance, no sorting/grouping. A subtype like ListCollectionView is always preferred. This is easy as most of the time, physical collection is some kind of IList. Therefore, whenever we retrieve the view as a CV, we almost always cast it to a subtype.