In MVVM, I regularly have output properties, or properties that usually depend on one or more other properties within the viewmodel. For example, say we have two input properties, ‘FirstName’ and ‘LastName’. The output field would be a string.Format() of these two fields showing the full name.
Simple VM:
The problem here, if you have had experience with MVVM before, is fairly obvious. I need to Notify the UI to update FullName. I have to do it whenever FirstName or LastName changes. The weird thing is, I have to do it in the setter.
For a more “exotic” example. Let’s say there is a third input for their favorite color. Another output property ‘Sentennce’ depends now on the FullName and the Favorite Color properties.
Ok, sure let’s just apply the same logic…not so fast. FullName doesn’t have a setter. So I need to call OnPropertyChanged() in the things that FullName depends on, which is FirstName and LastName. So I’ll place the updates in both properties setters.
This code is starting to smell. We have setters becoming full of notify the UI of changes for properties that aren’t directly associated with them. I’ve seen code with something like:
Just because they (I) couldn’t keep track of all the dependencies.
Well there Is A Better Way™. ReactiveUI which uses Reactive Extensions (Rx) allows us to create a pipeline effect for our notifications.
I’ll show the complete viewmodel before we make any changes:
First, we’ll get ReactiveUI from NuGet. Then we’ll replace our INotifyChanged with ReactiveObject. That forces us to change the setters. That’s ok, there’s a nice method for checking for update changed and raise all in one call. this.RaiseAndSetIfChanged().
Ok, but now we’re back to not notifying the FullName or Sentence properties. Right, we need to talk about some more ReactiveUI first. Specifically, WhenAnyValue, ObservableAsPropertyHelper and ToProperty.
WhenAnyValue allows us to get notified when a property changes.
This will let us know whenever there are changes to either FirstName or LastName and create a new object that contains both.
Now ObservableAsPropertyHelper and ToProperty go hand in hand. ObservableAsPropertyHelper boiler plate for an output property in ReactiveUI. ToProperty allows us to set this property.
Now we can see the train of how FullName will get it’s value. Anytime FirstName or LastName update, select a string.Format() of them and update the fullname property.
Ok, well lets fix Sentence:
Now we see the true intent. Anytime FullName or FavoriteColor is updated, we should change the SentenceProperty.