Reply to comment
Custom change listeners
A user asked.
When I use a viewmodel as a datacontext everything just works. Now I want to add a listener to the viewmodel of my own design, but am stumped. Do you have any suggestions? How do I hook up custom change listeners?
It all depends upon what you want to do with the notification. If you want to use that notification to update something else, I’d recommend using a Dependent instead of an event.
Updating a dependent
Where Independent has OnGet() and OnSet(), Dependent has only OnGet(). You can't directly set a dependent field. It's value is determined by an update method. You pass the update method to the constructor.
Here is an example dependent field.
private class PersonViewModel { private Person _person; private string _fullName; private Dependent _depFullName; public PersonViewModel(Person person) { _person = person; _depFullName = new Dependent(UpdateFullName); } public string FullName { get { _depFullName.OnGet(); return _fullName; } } private void UpdateFullName() { _fullName = string.Format("{0}, {1}", _person.LastName, _person.FirstName); } }
The UpdateFullName method is called only when the full name is out-of-date. If you access FullName again without changing the person’s name, the method is not called a second time.
The advantage of Dependent over events is dependency management. If you used events, you would have to know which events to subscribe to. Dependent, on the other hand, discovers its dependencies. This is why you use Update Controls instead of INotifyPropertyChanged in the first place.
Firing an event
But suppose that you need to notify something else for a different reason. Maybe you need to send a message to an external system. In this case, you can hook the Invalidated event of the Dependent. Add the hook to the constructor, like this:
public PersonViewModel(Person person) { _person = person; _depFullName = new Dependent(UpdateFullName); _depFullName.Invalidated += delegate { Dispatcher.CurrentDispatcher.BeginInvoke(() => { if (FullNameChanged != null) FullNameChanged(); }); }; }
The Invalidated event is fired whenever the Dependent becomes out-of-date. One of the Independent fields upon which it depends has just changed.
It is very important that your Invalidated handler does not try to synchronously get the updated value. The Independent field may not have its new value, yet. And even if it did, there may be additional changes coming. That is why the above example fires the FullNameChanged event asynchronously.
By the way, the code above is exactly how UpdateControls.XAML implements INotifyPropertyChanged.
Remember that Update Controls replaces imperative events with declarative dependency discovery. If you can avoid firing events, your application will be less brittle. But if you really need events, you can get them.

Recent comments
2 weeks 2 days ago
8 weeks 4 days ago
8 weeks 4 days ago
8 weeks 5 days ago
8 weeks 6 days ago
11 weeks 4 days ago
11 weeks 5 days ago
12 weeks 4 days ago
12 weeks 5 days ago
13 weeks 18 hours ago