Click here to Skip to main content
12,751,832 members (30,453 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as


25 bookmarked
Posted 26 May 2014

INotifyPropertyChanged Propagator

, 10 Jan 2017 CPOL
Rate this:
Please Sign up or sign in to vote.
Free and elegant way to propagate changes of dependent properties when dependency changed (including dynamically changeable nested properties)


Instead of this code I strongly recommend to use Stephen's Cleary Nito.CalculatedProperties library:  

Turned out Mr Cleary developed and published his library about the same time as I created my code so I wasn't aware of it. It is far more flexible and elegant than my solution, it's extremely simple and useful yet not so many people know about it.


Here is the free and elegant way to propagate changes of dependent properties when dependency changed (including dynamically changeable nested properties).


Most popular and naive implementation of INotifyPropertyChanged looks something like this:

public decimal TotalPrice
    get { return UnitPrice * Qty; }
    public int Qty
    get { return _qty; }
        _qty = value;
        RaisePropertyChanged(() => Qty);
        RaisePropertyChanged(() => TotalPrice);
public decimal UnitPrice
    get { return _unitPrice; }
        _unitPrice = value;
        RaisePropertyChanged(() => UnitPrice);
        RaisePropertyChanged(() => TotalPrice);

It has one well known design flaw: independent properties know their dependencies (Qty and UnitPrice in this example know that TotalPrice depends on them).
It's not a big problem for small apps however in complex view model hierarchies, bookkeeping code grows fast and things get out of control pretty quickly.

Wouldn't it be cool to have something like Microsoft Excel sheet instead? You just type a formula depending on other cells while those cells have no idea what depends on them.

Existing Solutions

This problem has been recognized by the community and number of possible solutions already exist. Why do we need another one? Well, let's check what we already have:

UpdateControls. Very promising and working solution. However it requires to abandon INotifyPropertyChanged along with good old {Binding} extensions and converters which is not easy in legacy code. Plus one should have some courage to give it a try on new commercial projects.

Fody (successor of Notify Property Weaver). Here we are stepping into the realm of IL-rewriters. Fody is free, fast and good. Unfortunately, it has a big limitation - namely it analyzes dependencies only in limits of one class, i.e., it won't propagate calculated property if it depends on a property of nested/child view model.

PostSharp. Also IL-rewriting solution, it has the same benefits that Fody plus it perfectly handles nested dependencies. Hooray! Unfortunately INotifyPropertyChanged implementation is a part of PostSharp Ultimate which is expensive (589 EUR as of 27 May 2014).

This list is not full obviously, there are other possible solutions with other or similar limitations. However, it looks like only PostSharp solves the problem to the full extent and unfortunately, it's not free.

Introducing PropertyChangedPropagator

Long story short, it's better to explain how to use it by example (pay attention to statements in bold):

public int Qty
    get { return _qty; }
    set { Set(ref _qty, value); }

public decimal UnitPrice
    get { return _unitPrice; }
    set { Set(ref _unitPrice, value); }

public decimal TotalPrice
        RaiseMeWhen(this, has => has.Changed(_ => _.UnitPrice, _ => _.Qty));
        return UnitPrice * Qty;

public decimal ExchTotalPrice
        RaiseMeWhen(this, has => has.Changed(_ => _.TotalPrice, _ => _.ExchangeRate));
        RaiseMeWhenDynamic(ExchangeRate, has => has.Changed(_ => _.Rate));
        return TotalPrice * ExchangeRate.Rate;

public ExchangeRateViewModel ExchangeRate
    get { return _exchangeRate; }
    set { Set(ref _exchangeRate, value); }

As you can see, the initial example has been turned inside out - Qty and UnitPrice properties (and ExchangeRate.Rate property of nested view model) don't know if there is anything depending on them, they just mind to fire their own notifications. And calculated properties say explicitly "yes, I'm depending on this and that, please raise me when some of those have changed".

How does RaiseMeWhen know which property to propagate? It uses [CallerMemberName] attribute:

public void RaiseMeWhen<T>(T dep, Action<IRaiseMeWhenHas<T>> has, 
    [CallerMemberName] string propertyName = null) ...   

Though my solution does violate "don't repeat yourself" principle (as well as initial naive example), it encourages to declare dependencies just where they belong - in getters of dependent properties.

Advanced Details

The trickiest part here is RaiseMeWhenDynamic. It should be used if some property depends on a property of nested view model and this nested view model itself is a subject to change at runtime. Sounds complicated, but in fact quite simple. In the attached example, we can choose one of ExchangeRateViewModel nested view models and change Rate property of currently active object.

A drawback of dynamic dependencies is that if there are several nested dependencies of the same type, then it's required to add some string hint to distinguish one dynamic dependency from another (fortunately this situation is rare). Consider the pseudo code:

public string CurrentContactName
// PrimaryContact and SecondaryContact are of same type so have to use hints
        "Primary", has => has.Changed(_ => _.Name));
        "Secondary", has => has.Changed(_ => _.Name));
        return (PrimaryContact ?? SecondaryContact).Name;

One of undeservedly little-known features of INotifyPropertyChanged is to fire PropertyChanged event with string.Empty property name which means "hey, the whole object changed, refresh all properties". RaiseMeWhen allows to do just that if invoked from constructor (NOTE: It doesn't work for dynamic dependencies). Another aggressive approach is to raise notification when any property of nested view model changed. The code below demonstrates both features:

public MyViewModel(NestedViewModel nested)
    NestedVm = nested;
    RaiseMeWhen(NestedVm, has => has.ChangedAny());

Usage of PropertyChangePropagator might look like declarative code but there is no IL rewriting and the implementation is perfectly imperative. Which means that all propagation subscriptions are lazily created (or dynamically modified in case of dynamic subscriptions) only if getter of dependent property is invoked. In human words - if nobody reads the calculated property, then it won't be propagated. This "feature-like bug" is usually not a problem in real life (after all, you declare properties for views to read them), but makes unit testing a bit more tricky. :-) Check out the source code for details.

The implementation is also thread-safe and uses weak subscriptions, so it's safe to declare dependencies on long-living publishers as subscribers will be eligible for garbage collection when they go out of scope. There is also an implementation trick to optimize memory usage.

I highly recommend to download and run the source code to see more details.


The solution includes performance tests which gives 1.5-2x times slower results than naive implementation. Analogue in PostSharp is 9 times slower on my machine, I didn't include it in the attached code though because of license dependency. In general, performance will depend on actual complexity of your view models' hierarchy.

Subscription callbacks created lazily on first getter invocation and then cached. In case of dynamic dependencies, subscriptions will be recreated on subsequent read after reference to the dynamic child view model changed.

Lambda expression trees to specify dependencies are themselves part of "has" callback's body and therefore constructed only once during subscription:

RaiseMeWhen(this, has => has.Changed(_ => _.TotalPrice, _ => _.ExchangeRate));

Propagation handlers made static to optimize memory footprint, i.e., same instances of generated methods are used for multiple view models of the same type. See StaticPropertyChangedHandlersCache class for implementation details.

How to Add This to My Project?

Easy! Copy PropertyChangedPropagator.cs and WeakEventListener.cs and check BindableBaseEx.cs to get the idea how to include RaiseMeWhen* methods in your base view model class.

It works equally well in WPF and WinRT (didn't try Silverlight, but must be good too).

Possible Improvements

It would be good to add support of ObservableCollection<T> and to find some way to work with multiple dynamic dependencies of the same type without string hints.


PropertyChangedPropagator can be used as a free and easy solution to propagate property dependencies. It works nicely with legacy code and can be adopted gradually. However if you already have PostSharp Ultimate licence (or spare money for it), then I'd recommend to use it as it's a more mature solution with official support.


  • 5 June 2014; Added Performance section
  • 27 May 2014: Initial version


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Nick Dunets
Software Developer
New Zealand New Zealand
Passionate .NET developer since times of C# 1.0
Originally from Belarus, moved to New Zealand in 2013

You may also be interested in...

Comments and Discussions

QuestionGOOD JOB Pin
mikor-soft16-Feb-17 23:48
membermikor-soft16-Feb-17 23:48 
GeneralMy vote of 5 Pin
Assil10-Jan-17 9:10
professionalAssil10-Jan-17 9:10 
QuestionDownload Pin
Member 78373512-Sep-15 11:47
memberMember 78373512-Sep-15 11:47 
AnswerRe: Download Pin
Shadowcouncil10-Jan-16 11:03
memberShadowcouncil10-Jan-16 11:03 
GeneralMy vote of 5 Pin
DVL Patel15-Feb-15 20:19
professionalDVL Patel15-Feb-15 20:19 
GeneralSimilar projects Pin
ncdahlquist24-Nov-14 9:47
memberncdahlquist24-Nov-14 9:47 
GeneralRe: Similar projects Pin
Nick Dunets14-Nov-16 17:02
memberNick Dunets14-Nov-16 17:02 
QuestionNot bad. Pin
Pete O'Hanlon27-May-14 3:52
protectorPete O'Hanlon27-May-14 3:52 
AnswerRe: Not bad. Pin
Nick Dunets27-May-14 11:01
memberNick Dunets27-May-14 11:01 
GeneralRe: Not bad. Pin
William E. Kempf30-May-14 10:37
memberWilliam E. Kempf30-May-14 10:37 
GeneralRe: Not bad. Pin
Nick Dunets4-Jun-14 13:16
memberNick Dunets4-Jun-14 13:16 
GeneralRe: Not bad. Pin
wkempf5-Jun-14 3:30
memberwkempf5-Jun-14 3:30 
GeneralRe: Not bad. Pin
Nick Dunets5-Jun-14 11:37
memberNick Dunets5-Jun-14 11:37 
QuestionNice, I quite like this Pin
Sacha Barber27-May-14 3:30
mvpSacha Barber27-May-14 3:30 
AnswerRe: Nice, I quite like this Pin
Pete O'Hanlon27-May-14 8:47
protectorPete O'Hanlon27-May-14 8:47 
AnswerRe: Nice, I quite like this Pin
Nick Dunets27-May-14 11:09
memberNick Dunets27-May-14 11:09 
QuestionCan you post the code ? Pin
melnac27-May-14 1:02
membermelnac27-May-14 1:02 
AnswerRe: Can you post the code ? Pin
Nick Dunets27-May-14 10:59
memberNick Dunets27-May-14 10:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170217.1 | Last Updated 10 Jan 2017
Article Copyright 2014 by Nick Dunets
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid