Brian Genisio's House of Bilz

  Home  |   Contact  |   Syndication    |   Login
  62 Posts | 0 Stories | 118 Comments | 0 Trackbacks

News

Locations of visitors to this page

Archives

Post Categories

Who am I?

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

Feedback

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged 11/14/2009 4:30 PM Gustavo Keener
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).

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged 1/10/2010 9:25 PM Rapid Share
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.

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged 1/31/2010 9:41 AM Paul Kohler
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 :-)

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: