INotifyPropertyChanged (3 of 3) – without the reversed notifications

8
April 8, 2013 // wpf

Welcome back for part 3 in this INotifyPropertyChanged series. This time we’ll be taking a look at reversed notifications which are another code smell with this pattern.

Reversed notifications

What do I mean by reversed notifications? When you have a dependent property (FullName) which is calculated based on an independent property (FirstName) then you have to make sure you raise notifications for FullName whenever FirstName changes. Since there isn’t a direct way to do this, a common approach is to have the source directly do the work for the destination:

        public string FirstName
        {
            get { return GetPropertyValue<string>(); }
            set
            {
                if (SetPropertyValue(value))
                {
                    RaisePropertyChanged("FullName");
                }
            }
        }

        public string FullName
        {
            get { return string.Format("{0} {1} {2}", FirstName, MiddleName, LastName); }
        }

It works, but it is putting the knowledge of the dependency between the properties in the wrong place. With this approach, the independent property (FirstName) has to be aware of all of its dependencies (FullName). It would be much better if the dependent property could take care of itself. So how do we flip this around in the right direction?

NotifiesOnAttribute

Using attributes, we can specify our dependencies directly on the dependent property – leaving the independent property untouched!

        public string FirstName
        {
            get { return GetPropertyValue<string>(); }
            set { SetPropertyValue(value); }
        }

        [NotifiesOn("FirstName")]
        public string FullName
        {
            get { return string.Format("{0} {1} {2}", FirstName, MiddleName, LastName); }
        }

Magic! 😉

Ok, lets peek behind the scenes to see how that is being accomplished. We have defined a NotifiesOnAttribute class which simply takes a string parameter pointing to the independent property. We’ve also set the AttributeUsage to allow for the property to be defined multiple times. So in our example above we can also be notified when MiddleName and LastName change by repeating the attribute definition. In our view model, we do a lazy-initialized pull of all the attribute definitions on our class and store them in an ILookup structure which is basically a dictionary without unique keys. Finally when we are raising property changed, we check our cache of dependent properties and if any are found then we raise PropertyChanged on them as well.

        private ILookup<string, string> _dependentLookup;

        private ILookup<string, string> DependentLookup
        {
            get
            {
                return _dependentLookup ?? (_dependentLookup = (from p in GetType().GetProperties()
                                                                let attrs = p.GetCustomAttributes(typeof(NotifiesOnAttribute), false)
                                                                from NotifiesOnAttribute a in attrs
                                                                select new { Independent = a.Name, Dependent = p.Name }).ToLookup(i => i.Independent, d => d.Dependent));
            }
        }

        protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            if (propertyName == null) throw new ArgumentNullException("propertyName");

            var propertyChanged = PropertyChanged;
            if (propertyChanged != null)
            {
                propertyChanged(this, new PropertyChangedEventArgs(propertyName));

                foreach (var dependentPropertyName in DependentLookup[propertyName])
                {
                    RaisePropertyChanged(dependentPropertyName);
                }
            }
        }

Tada!

Performance

We’re almost done, but we still have to check out our performance. I’ve modified the sample application (below) that raises a million notifications using both mechansims. Here’s the results:

Performance image

Performance comparison between direct and attribute based mechanisms.

Our baseline took 9.565s, and our attribute approach took 10.099s – just about a 5% increase which works for me. 🙂

Summary

With attributes on our dependent property, we can not only cut down our code but we can also put our logic back in the right place. Thanks for reading these article(s). I hope you enjoyed them and if you have other ideas on how to improve the INotifyPropertyChanged pattern please chime in on the comments. 🙂

Code: SteveCadwallader.NotifyPropertyChanged.3of3.zip

Part 1: INotifyPropertyChanged (1 of 3) – without the strings
Part 2: INotifyPropertyChanged (2 of 3) – without the backing fields

About the author

Steve Cadwallader is a software developer who geeks out on user interfaces, clean code and making things easier.

8 Comments

  1. Steve, thank you very much! Both for your work on CodeMaid which is my favourite VS Extension and the tool that I teach every new developer I coach to use all the time and for these very nice articles here.

    I’ll be looking forward to implement these solutions in our own code!

    Best regards,
    Timo

  2. Wow, that’s really nice! The only thing that bothers me is the fragility of passing a string into the attribute. I can’t find any way around it, but even so this is a huge improvement!

    • I’m glad you like it. 🙂

      Agreed about passing a string into the attribute, but unfortunately all the research I did pointed that lambdas or other complex expressions couldn’t be defined inside an attribute. If you ever think of an alternative, I’d be excited to hear about it. 🙂

      • It would be great to have this checked at compile time, but since that doesn’t seem possible how about a check at run time? You could verify that the string is a valid property name when building _dependentLookup. If not, throw an exception saying “NotifiesOnAttribute is not valid because ‘Foobar’ is not a property of ‘SomeClass’.”

        Run time exceptions are not ideal, but neither is having broken property change notifications…

        • I like it, perhaps a part 4 post some day.. 🙂

        • I do exactly this. (Sort of.) Only for #if DEBUG, I check the property name passed to my OnPropertyChanged and throw an Exception if it doesn’t exist in the class. That should catch all typos and forgotten calls during developer tests and not do any unexpected harm in the release. (Code can be found in current projects on my website.)

          BTW, great articles! I think I can further simplify my ViewModelBase class from that. But the 70 % overhead for the lambdas are scary – and I’m already using those… I definitely need to do some performance checks again. Unfortunately, I still deal a lot with VS 2010 so I can’t use the caller name attribute thing.

  3. Very nice article … I create my own framework MVVM to better understand all concept in this pattern and your articles are very helpfull.

    Continue … 😀

Leave a Comment