Geeks With Blogs

News Locations of visitors to this page
Brian Genisio's House of Bilz

More Adventures in MVVM Shout it kick it on DotNetKicks.com

I spend a lot of time writing ViewModels, which almost always implements INotifyPropertyChanged.  For those who are not familiar with this interface, it includes a single event: PropertyChanged.  That event contains a payload of the name of the property that changed.  It exists as a standard way to notify observers that a property needs to be re-evaluated.

Although I use it all the time, I have always believed that INotifyPropertyChanged has some serious shortcomings.  One of those shortcomings deals with dependant properties. 

Lets say, for for the sake of example, that the ViewModel has two integer properties that the user can enter (InputA and InputB).  There also exists a property named Calculation that is dependent upon InputA and InputB.  Finally, there is a display property named CalculationText which is dependent upon Calculation.  The code for these properties would look like this:

private int _inputA;
public int InputA
{
    get { return _inputA; }
    set
    {
        if (_inputA == value) return;

        _inputA = value;
        RaisePropertyChanged("InputA");
        RaisePropertyChanged("Calculation");
        RaisePropertyChanged("CalculationText");
    }
}

private int _inputB;
public int InputB
{
    get { return _inputB; }
    set
    {
        if (_inputB == value) return;

        _inputB = value;
        RaisePropertyChanged("InputB");
        RaisePropertyChanged("Calculation");
        RaisePropertyChanged("CalculationText");
    }
}

public int Calculation
{
    get { return InputA * InputB; }
}

public string CalculationText
{
    get { return "A * B = " + Calculation; }
}

There is a problem with this code.  The input properties need to know that they are inputs for Calculation and CalculationText by firing the event for the calculations.  As far as I am concerned, this is the wrong place for this information to exist.  Inputs should not know that they are inputs.  I can say first hand that this quickly breaks down as the ViewModel gets bigger and you start changing behavior.

The responsibility should be reversed.  Instead of having the input properties knowing about the dependants, the dependent properties should be responsible for knowing the inputs that they rely upon.  This can be done with some simple declarations:

private int _inputA;
public int InputA
{
    get { return _inputA; }
    set
    {
        if (_inputA == value) return;

        _inputA = value;
        RaisePropertyChanged("InputA");
    }
}

private int _inputB;
public int InputB
{
    get { return _inputB; }
    set
    {
        if (_inputB == value) return;

        _inputB = value;
        RaisePropertyChanged("InputB");
    }
}

[DependsUpon("InputA")]
[DependsUpon("InputB")]
public int Calculation
{
    get { return InputA * InputB; }
}

[DependsUpon("Calculation")]
public string CalculationText
{
    get { return "A * B = " + Calculation; }
}

Notice how Calculation declares that it is dependent upon InputA and InputBCalculationText also declares a dependency upon Calculation.  The inputs are free of knowing anything about the dependants.

The implementation of this behavior should be handled in the base class and there are several ways to accomplish it.  There are just a few things you want to think about:

  1. Make sure that when inputs fire a change notification, the dependants are also fired
  2. Make sure to handle dependency chaining.  InputA will cause Calculation to fire and Calculation will cause CalculationText to fire
  3. If the derived class declares dependencies such that it creates a circular reference, don’t endlessly loop or overflow your stack

Here is a very simple implementation of this behavior.  It manages the reflection at the time of change.  A better (more efficient) implementation would probably map the dependencies at construction time into a private dictionary, but this is just a quick example of how you might achieve this behavior:

public abstract class ViewModelBase : INotifyPropertyChanged
{
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
    protected class DependsUponAttribute : Attribute
    {
        public string DependancyName { get; private set; }
        
        public DependsUponAttribute(string propertyName)
        {
            DependancyName = propertyName;
        }
    }

    protected virtual void RaisePropertyChanged(string propertyName)
    {
        var handlers = PropertyChanged;
        if (handlers != null)
        {
            foreach(var property in AllNotifiedProperties(propertyName))
                handlers(this, new PropertyChangedEventArgs(property));
        }
    }

    private IEnumerable<string> DependantProperties(string inputName)
    {
        return from property in GetType().GetProperties()
               where property.GetCustomAttributes(typeof(DependsUponAttribute), true).Cast<DependsUponAttribute>()
                     .Any(attribute => attribute.DependancyName == inputName)
               select property.Name;
    }

    private IEnumerable<string> NotifiedProperties(IEnumerable<string> inputs)
    {
        var dependancies = from input in inputs
                           from dependancy in DependantProperties(input)
                           select dependancy;

        return inputs.Union(dependancies).Distinct();
    }

    private IEnumerable<string> AllNotifiedProperties(string inputName)
    {
        IEnumerable<string> results = new[]{inputName};

        while (NotifiedProperties(results).Count() > results.Count())
            results = NotifiedProperties(results);

        return results;
    }

    public event PropertyChangedEventHandler PropertyChanged;
}
Posted on Saturday, November 14, 2009 1:55 PM | Back to top


Comments on this post: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged
Requesting Gravatar...
Using of Attributes to indicate dependencies strikes me as a brilliant idea. It solves the problem without necessarily having to use the Decorator pattern (unless you want to do this kind of thing at runtime).
Left by Gustavo Keener on Nov 14, 2009 4:30 PM

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged
Requesting Gravatar...
That's something that bugs me a lot.
A very nice way to implement that is to use postsharp (postsharp.org). You just put an attribute on your entity the framework takes care of the rest.
Left by Rapid Share on Jan 10, 2010 9:25 PM

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged
Requesting Gravatar...
Nice idea with the View Model, I like how it walks the property tree.

We use the "DependsUponAttribute" idea in a current site with large numbers of dependencies around validation and the display of data. Being able to add or remove attributes and have the UI react is real nice!

PK :-)
Left by Paul Kohler on Jan 31, 2010 9:41 AM

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged
Requesting Gravatar...
That's something that bugs me a lot.
A very nice way to implement that is to use postsharp (postsharp.org). You just put an attribute on your entity the framework takes care of the rest.
Left by Best Car Rental on May 09, 2010 10:22 PM

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged
Requesting Gravatar...
We use the "DependsUponAttribute" idea in a current site with large numbers of dependencies around validation and the display of data. Being able to add or remove attributes and have the UI react is real nice!

great udea dyde
Left by olympus u tough 3000 on May 20, 2010 10:33 PM

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged
Requesting Gravatar...
You have saved me a lot of time! I am a long time could not find a bug in my code. Thank you!
Left by Lost on May 26, 2010 7:02 PM

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged
Requesting Gravatar...
I was messing with this for like 3 hours, a pain in the ass if you asked me. This helped.
Left by How to get a girlfriend on May 27, 2010 8:30 PM

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged
Requesting Gravatar...
Very good post. I stumbled on your blog and wanted to say that I really enjoyed reading your blog. Either way I will subscribe to their feed, and I hope to publish news soon.Online again, I've been looking a little help.I admire what you've done here. Good to see your light on this important topic can be easily seen. Awesome post and wait for the next update.
Left by santa letters on Jun 05, 2010 7:16 AM

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged
Requesting Gravatar...


Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged (houseofbilz.com)

submitted by BrianGenisioBrianGenisio(885) 6 months, 23 days ago

Although I use it all the time, I have always believed that INotifyPropertyChanged has some serious shortcomings. One of those shortcomings deals with dependant properties. This article discusses how to fix that problem by inverting the responsibility of notifying the change from the input properties to the dependant properties.
Left by Auto Glass on Jun 07, 2010 8:42 AM

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged
Requesting Gravatar...
I'm super excited to try this application! Very good choice of picture: Avril Lavigne is too powerful! : D
Left by Cheap led TV on Jun 10, 2010 5:49 AM

Your comment:
 (will show your gravatar)


Copyright © Brian Genisio's House Of Bilz | Powered by: GeeksWithBlogs.net