Brian Genisio's House of Bilz

  Home  |   Contact  |   Syndication    |   Login
  72 Posts | 0 Stories | 187 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 :-)

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged 5/9/2010 10:22 PM Best Car Rental
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 5/20/2010 10:33 PM olympus u tough 3000
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

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

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

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged 6/5/2010 7:16 AM santa letters
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.

# re: Adventures in MVVM -- Dependant Properties with INotifyPropertyChanged 6/7/2010 8:42 AM Auto Glass


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.

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

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