63

Is there any way to automatically get notified of property changes in a class without having to write OnPropertyChanged in every setter? (I have hundreds of properties that I want to know if they have changed).


Anton suggests dynamic proxies. I've actually used the "Castle" library for something similar in the past, and while it does reduce the amount of code I've had to write, it added around 30 seconds to my program startup time (ymmv) - because it's a runtime solution.

I'm wondering if there is a compile time solution, maybe using compile-time attributes...


Slashene and TcKs give suggestions which generates repetitive code - unfortunately, not all my properties are a simple case of m_Value = value - lots of them have custom code in the setters, so cookie-cutter code from snippets and xml aren't really feasible for my project either.

user990423
  • 1,397
  • 2
  • 12
  • 32
Tim Gradwell
  • 2,312
  • 5
  • 24
  • 25
  • Looks like the answer is no then – Jodrell May 26 '11 at 15:38
  • I think this [T4 + attribute method](http://www.scottlogic.co.uk/blog/colin/2009/08/declarative-dependency-property-definition-with-t4-dte/) of implementing INPC is pretty sweet. –  May 17 '10 at 13:27
  • 1
    You can use [dynamic proxies](http://www.nablasoft.com/alkampfer/index.php/2008/08/04/implement-inotifypropertychanged-with-castledynamicproxy/). – Anton Gogolev Feb 09 '09 at 10:12
  • I helped to make a class to generate a proxy on the fly implementing `INotifyPropertyChanged` and changes detection: http://www.codeproject.com/KB/cs/INotifyPropertyChanged.aspx – Eduardo Mardini Nov 26 '11 at 14:48

13 Answers13

48

EDIT: The author of NotifyPropertyWeaver has deprecated the tool in favor of the more general Fody. (A migration guide for people moving from weaver to fody is available.)


A very convenient tool I've used for my projects is Notify Property Weaver Fody.

It installs itself as a build step in your projects and during compilation injects code that raises the PropertyChanged event.

Making properties raise PropertyChanged is done by putting special attributes on them:

[ImplementPropertyChanged]
public string MyProperty { get; set; }

As a bonus, you can also specify relationships for properties that depend on other properties

[ImplementPropertyChanged]
public double Radius { get; set; }

[DependsOn("Radius")]
public double Area 
{
    get { return Radius * Radius * Math.PI; }
}
Isak Savo
  • 34,957
  • 11
  • 60
  • 92
  • 2
    Fody / PropertyChanged automatically picks up property dependencies, so in the example the Area property does not need [DependsOn("Radius")] attribute: the tool detects this dependency automatically. – Edward Nov 18 '13 at 14:47
  • 1
    @Edward this is true for this example, however I've noticed that it is better to explicitly define most dependencies, as Fody doesn't pick up all of them. – Ben Winding Dec 09 '15 at 00:27
  • 1
    @IsakSavo BTW. `Fody` is the IL Wiever framework, `Fody.PropertyChanged` is the Plugin used to implement `INotifyPropertyChanged` – Meirion Hughes Mar 06 '16 at 07:23
  • Fody won't work in Windows 10 UWP apps. Any workaround/alternatives? – Vijay Chavda Apr 15 '17 at 16:31
  • What do dependencies do? – jeromej Jul 23 '19 at 17:00
  • 1
    Beware in the new Fody API, you don't have to decorate classes/properties with `[ImplementPropertyChanged]`. It will automatically implement `INotifyPropertyChanged ` for all classes that inherit it. – Shabgard Aug 20 '20 at 14:20
39

The nameof operator was implemented in C# 6.0 with .NET 4.6 and VS2015 in July 2015. The following is still valid for C# < 6.0

We use the code below (From http://www.ingebrigtsen.info/post/2008/12/11/INotifyPropertyChanged-revisited.aspx). Works great :)

public static class NotificationExtensions
{
    #region Delegates

    /// <summary>
    /// A property changed handler without the property name.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="sender">The object that raised the event.</param>
    public delegate void PropertyChangedHandler<TSender>(TSender sender);

    #endregion

    /// <summary>
    /// Notifies listeners about a change.
    /// </summary>
    /// <param name="EventHandler">The event to raise.</param>
    /// <param name="Property">The property that changed.</param>
    public static void Notify(this PropertyChangedEventHandler EventHandler, Expression<Func<object>> Property)
    {
        // Check for null
        if (EventHandler == null)
            return;

        // Get property name
        var lambda = Property as LambdaExpression;
        MemberExpression memberExpression;
        if (lambda.Body is UnaryExpression)
        {
            var unaryExpression = lambda.Body as UnaryExpression;
            memberExpression = unaryExpression.Operand as MemberExpression;
        }
        else
        {
            memberExpression = lambda.Body as MemberExpression;
        }

        ConstantExpression constantExpression;
        if (memberExpression.Expression is UnaryExpression)
        {
            var unaryExpression = memberExpression.Expression as UnaryExpression;
            constantExpression = unaryExpression.Operand as ConstantExpression;
        }
        else
        {
            constantExpression = memberExpression.Expression as ConstantExpression;
        }

        var propertyInfo = memberExpression.Member as PropertyInfo;

        // Invoke event
        foreach (Delegate del in EventHandler.GetInvocationList())
        {
            del.DynamicInvoke(new[]
            {
                constantExpression.Value, new PropertyChangedEventArgs(propertyInfo.Name)
            });
        }
    }


    /// <summary>
    /// Subscribe to changes in an object implementing INotifiyPropertyChanged.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="ObjectThatNotifies">The object you are interested in.</param>
    /// <param name="Property">The property you are interested in.</param>
    /// <param name="Handler">The delegate that will handle the event.</param>
    public static void SubscribeToChange<T>(this T ObjectThatNotifies, Expression<Func<object>> Property, PropertyChangedHandler<T> Handler) where T : INotifyPropertyChanged
    {
        // Add a new PropertyChangedEventHandler
        ObjectThatNotifies.PropertyChanged += (s, e) =>
            {
                // Get name of Property
                var lambda = Property as LambdaExpression;
                MemberExpression memberExpression;
                if (lambda.Body is UnaryExpression)
                {
                    var unaryExpression = lambda.Body as UnaryExpression;
                    memberExpression = unaryExpression.Operand as MemberExpression;
                }
                else
                {
                    memberExpression = lambda.Body as MemberExpression;
                }
                var propertyInfo = memberExpression.Member as PropertyInfo;

                // Notify handler if PropertyName is the one we were interested in
                if (e.PropertyName.Equals(propertyInfo.Name))
                {
                    Handler(ObjectThatNotifies);
                }
            };
    }
}

Used for example this way:

public class Employee : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private string _firstName;
    public string FirstName
    {
        get { return this._firstName; }
        set
        {
            this._firstName = value;
            this.PropertyChanged.Notify(()=>this.FirstName);
        }
    }
}

private void firstName_PropertyChanged(Employee sender)
{
    Console.WriteLine(sender.FirstName);
}

employee = new Employee();
employee.SubscribeToChange(() => employee.FirstName, firstName_PropertyChanged);

Some syntax errors in the example may exist. Didn't test it. But you should have the concept there at least :)

EDIT: I see now that you may have wanted even less work, but yeah... the stuff above at least makes it a lot easier. And you prevent all the scary problems with refering to properties using strings.

Ian Ringrose
  • 51,220
  • 55
  • 213
  • 317
Svish
  • 152,914
  • 173
  • 462
  • 620
  • 2
    I'd consider a) refactoring your Expression -> property name code into another method and b) resolving the property _before_ you subscribe to the PropertyChanged event (otherwise you're running that code every time) – Richard Szalay Nov 02 '11 at 12:51
  • @Richard Good idea. Feel free to edit, just make sure it works first, so we don't end up with faulty code here :) – Svish Nov 02 '11 at 13:01
  • Did you just added a class to replace built-in `nameof`? It was very long time ago, I'm curious, was that the time `nameof` wasn't available in .NET? Now you definitely should use `nameof` instead of `Reflection` because it's compile-time, thus way faster. For now you will probably agree - `Fody` is just perfect to handle a lot of DTOs, but when you don't have too much of them - just do it manual - it's faster both in coding time and in performance. – Harry Oct 03 '21 at 06:21
37

The Framework 4.5 provides us with the CallerMemberNameAttribute, which makes passing the property name as a string unnecessary:

private string m_myProperty;
public string MyProperty
{
    get { return m_myProperty; }
    set
    {
        m_myProperty = value;
        OnPropertyChanged();
    }
}

private void OnPropertyChanged([CallerMemberName] string propertyName = "none passed")
{
    // ... do stuff here ...
}

Similar to Svish's solution, just replacing lambda awesomeness with boring framework functionality ;-)

If you're working on Framework 4.0 with KB2468871 installed, you can install the Microsoft BCL Compatibility Pack via nuget, which also provides this attribute.

Community
  • 1
  • 1
takrl
  • 6,356
  • 3
  • 60
  • 69
11

You can have extension method on your PropertyChanged delegate and use it like this:

public string Name
{
    get { return name; }
    set
    {
        name = value;
        PropertyChanged.Raise(() => Name);
    }
}

Subscription to a specific property change:

var obj = new Employee();

var handler = obj.SubscribeToPropertyChanged(
    o => o.FirstName, 
    o => Console.WriteLine("FirstName is now '{0}'", o.FirstName));

obj.FirstName = "abc";

// Unsubscribe when required
obj.PropertyChanged -= handler;

extension method is able to determine sender and property name just by inspecting lambda expression tree and without major performance impact:

public static class PropertyChangedExtensions
{
    public static void Raise<TProperty>(
        this PropertyChangedEventHandler handler, Expression<Func<TProperty>> property)
    {
        if (handler == null)
            return;

        var memberExpr = (MemberExpression)property.Body;
        var propertyName = memberExpr.Member.Name;
        var sender = ((ConstantExpression)memberExpr.Expression).Value;
        handler.Invoke(sender, new PropertyChangedEventArgs(propertyName));
    }

    public static PropertyChangedEventHandler SubscribeToPropertyChanged<T, TProperty>(
        this T obj, Expression<Func<T, TProperty>> property, Action<T> handler)
        where T : INotifyPropertyChanged
    {
        if (handler == null)
            return null;

        var memberExpr = (MemberExpression)property.Body;
        var propertyName = memberExpr.Member.Name;

        PropertyChangedEventHandler subscription = (sender, eventArgs) =>
        {
            if (propertyName == eventArgs.PropertyName)
                handler(obj);
        };

        obj.PropertyChanged += subscription;

        return subscription;
    }
}

If PropertyChanged event is declared in a base type then it won't be visible as a delegate field in the derived classes. In this case a workaround is to declare a protected field of type PropertyChangedEventHandler and explicitly implement event's add and remove accessors:

public class Base : INotifyPropertyChanged
{
    protected PropertyChangedEventHandler propertyChanged;
    public event PropertyChangedEventHandler PropertyChanged
    {
        add { propertyChanged += value; }
        remove { propertyChanged -= value; }
    }
}

public class Derived : Base
{
    string name;

    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            propertyChanged.Raise(() => Name);
        }
    }
}
Konstantin Spirin
  • 20,609
  • 15
  • 72
  • 90
11

Implement a type safe INotifyPropertyChanged : See here

Then make your own code snippet :

private $Type$ _$PropertyName$;
public $Type$ $PropertyName$
{
    get
    {
        return _$PropertyName$;
    }
    set
    {
        if(value != _$PropertyName$)
        {
            _$PropertyName$ = value;
            OnPropertyChanged(o => o.$PropertyName$);               
        }
    }
}

With Code snippet designer and you have done ! Easy, secure way to build your INotifyPropertyChanged.

Vahid Farahmandian
  • 6,081
  • 7
  • 42
  • 62
Nicolas Dorier
  • 7,383
  • 11
  • 58
  • 71
4

you might want to look into Aspect-Oriented Programming as a whole

Frameworks => you could look at linfu

xmedeko
  • 7,336
  • 6
  • 55
  • 85
almog.ori
  • 7,839
  • 1
  • 35
  • 49
  • wish I could have do more than just +1, I strongly recommend to use some aspect-oriented framework when dealing WPF infrastructure – chester89 Oct 13 '11 at 15:01
4

I don't know no standard way, but I know two workarounds:

1) PostSharp can do it for you after the compilation. It is very usefull, but it take some time on every build.

2) Custom tool i Visual Studio. You can combine it with "partial class". Then you can create custom tool for your XML and you can generate source code from the xml.

For example this xml:

<type scope="public" type="class" name="MyClass">
    <property scope="public" type="string" modifier="virtual" name="Text" notify="true" />
</type>

can be source for this code:

public partial class MyClass {
    private string _text;
    public virtual string Text {
        get { return this._Text; }
        set {
            this.OnPropertyChanging( "Text" );
            this._Text = value;
            this.OnPropertyChanged( "Text" );
        }
    }
}
TcKs
  • 25,849
  • 11
  • 66
  • 104
2

You could look at Castle or Spring.NET and implementing interceptor functionality?

Neil Barnwell
  • 41,080
  • 29
  • 148
  • 220
2

I have just found ActiveSharp - Automatic INotifyPropertyChanged, I have yet to use it, but it looks good.

To quote from it's web site...


Send property change notifications without specifying property name as a string.

Instead, write properties like this:

public int Foo
{
    get { return _foo; }
    set { SetValue(ref _foo, value); }  // <-- no property name here
}

Note that there is no need to include the name of the property as a string. ActiveSharp reliably and correctly figures that out for itself. It works based on the fact that your property implementation passes the backing field (_foo) by ref. (ActiveSharp uses that "by ref" call to identify which backing field was passed, and from the field it identifies the property).

Ian Ringrose
  • 51,220
  • 55
  • 213
  • 317
1

Just to make the implementation quicker you can use a snippet

From http://aaron-hoffman.blogspot.it/2010/09/visual-studio-code-snippet-for-notify.html

the ViewModel classes of projects following the M-V-VM pattern it is often necessary to raise a "PropertyChanged" event (to assist with INotifyPropertyChanged interface implementation) from within a property's setter. This is a tedious task that will hopefully someday be solved by using the Compiler as a Service...

Snippet core (for which full credit goes to the author, who is not me) is the following

  <Code Language= "csharp "> 
    <![CDATA[public $type$ $property$ 
{ 
    get { return _$property$; } 
    set 
    { 
        if (_$property$ != value) 
        { 
            _$property$ = value; 
            OnPropertyChanged($property$PropertyName); 
        } 
    } 
} 
private $type$ _$property$; 
public const string $property$PropertyName = "$property$";$end$]]> 
</Code> 
usr-local-ΕΨΗΕΛΩΝ
  • 26,101
  • 30
  • 154
  • 305
1

There is no Single implementation of Property Changed that can handle every way that people want to use it. best bet is to generate a helper class to do the work for you here is an example of one i use

/// <summary>
/// Helper Class that automates most of the actions required to implement INotifyPropertyChanged
/// </summary>
public static class HPropertyChanged
{
    private static Dictionary<string, PropertyChangedEventArgs> argslookup = new Dictionary<string, PropertyChangedEventArgs>();
    public static string ThisPropertyName([CallerMemberName]string name = "")
    {
        return name;
    }

    public static string GetPropertyName<T>(Expression<Func<T>> exp)
    {
        string rtn = "";
        MemberExpression mex = exp.Body as MemberExpression;
        if(mex!=null)
            rtn = mex.Member.Name;
        return rtn;
    }

    public static void SetValue<T>(ref T target, T newVal, object sender, PropertyChangedEventHandler handler, params string[] changed)
    {
        if (!target.Equals(newVal))
        {
            target = newVal;
            PropertyChanged(sender, handler, changed);
        }
    }
    public static void SetValue<T>(ref T target, T newVal, Action<PropertyChangedEventArgs> handler, params string[] changed)
    {
        if (!target.Equals(newVal))
        {
            target = newVal;
            foreach (var item in changed)
            {
                handler(GetArg(item));
            }
        }
    }

    public static void PropertyChanged(object sender,PropertyChangedEventHandler handler,params string[] changed)
    {
        if (handler!=null)
        {
            foreach (var prop in changed)
            {
                handler(sender, GetArg(prop));
            }
        }
    }
    public static PropertyChangedEventArgs GetArg(string name)
    {
        if (!argslookup.ContainsKey(name)) argslookup.Add(name, new PropertyChangedEventArgs(name));
        return argslookup[name];
    }
}

edit: it was suggested that i shift from a helper class to a value wrapper and i've since been using this one and i find it works quite well

public class NotifyValue<T>
{
    public static implicit operator T(NotifyValue<T> item)
    {
        return item.Value;
    }

    public NotifyValue(object parent, T value = default(T), PropertyChangingEventHandler changing = null, PropertyChangedEventHandler changed = null, params object[] dependenies)
    {
        _parent = parent;
        _propertyChanged = changed;
        _propertyChanging = changing;

        if (_propertyChanged != null)
        {
            _propertyChangedArg =
                dependenies.OfType<PropertyChangedEventArgs>()
                .Union(
                    from d in dependenies.OfType<string>()
                    select new PropertyChangedEventArgs(d)
                );

        }
        if (_propertyChanging != null)
        {
            _propertyChangingArg =
                dependenies.OfType<PropertyChangingEventArgs>()
                .Union(
                    from d in dependenies.OfType<string>()
                    select new PropertyChangingEventArgs(d)
                );
        }
        _PostChangeActions = dependenies.OfType<Action>();

    }

    private T _Value;

    public T Value
    {
        get { return _Value; }
        set
        {
            SetValue(value);
        }
    }

    public bool SetValue(T value)
    {
        if (!EqualityComparer<T>.Default.Equals(_Value, value))
        {
            OnPropertyChnaging();
            _Value = value;
            OnPropertyChnaged();
            foreach (var action in _PostChangeActions)
            {
                action();
            }
            return true;
        }
        else
            return false;
    }

    private void OnPropertyChnaged()
    {
        var handler = _propertyChanged;
        if (handler != null)
        {
            foreach (var arg in _propertyChangedArg)
            {
                handler(_parent, arg);
            }           
        }
    }

    private void OnPropertyChnaging()
    {
        var handler = _propertyChanging;
        if(handler!=null)
        {
            foreach (var arg in _propertyChangingArg)
            {
                handler(_parent, arg);
            }
        }
    }

    private object _parent;
    private PropertyChangedEventHandler _propertyChanged;
    private PropertyChangingEventHandler _propertyChanging;
    private IEnumerable<PropertyChangedEventArgs> _propertyChangedArg;
    private IEnumerable<PropertyChangingEventArgs> _propertyChangingArg;
    private IEnumerable<Action> _PostChangeActions;
}

example of use

private NotifyValue<int> _val;
public const string ValueProperty = "Value";
public int Value
{
    get { return _val.Value; }
    set { _val.Value = value; }
}

then in constructor you do

_val = new NotifyValue<int>(this,0,PropertyChanged,PropertyChanging,ValueProperty );
MikeT
  • 5,398
  • 3
  • 27
  • 43
  • C#6.0 has introduced the nameof keyword that works like the typeof key word to automate the extraction of reflection data, allowing you to do without the constants – MikeT Aug 04 '15 at 10:07
  • I like it. I've done something similar, but a lot more lightweight (as you mentioned, everyone's requirements are different). I've called mine an EncapsulatedProperty. It just has a Value property, implicit conversions, and a ValueChanged event. If I'd just done this back when I'd asked my question 7 years ago, I'd have been happy with this solution :-) – Tim Gradwell Mar 04 '16 at 12:22
1

Amelioration to call event in children classes:

Called thanks to: this.NotifyPropertyChange(() => PageIndex);

Add this in the NotificationExtensions class:

    /// <summary>
    /// <para>Lève l'évènement de changement de valeur sur l'objet <paramref name="sender"/>
    /// pour la propriété utilisée dans la lambda <paramref name="property"/>.</para>
    /// </summary>
    /// <param name="sender">L'objet portant la propriété et l'évènement.</param>
    /// <param name="property">Une expression lambda utilisant la propriété subissant la modification.</param>
    public static void NotifyPropertyChange(this INotifyPropertyChanged sender, Expression<Func<Object>> property)
    {
        if (sender == null)
            return;

        // Récupère le nom de la propriété utilisée dans la lambda en argument
        LambdaExpression lambda = property as LambdaExpression;
        MemberExpression memberExpression;
        if (lambda.Body is UnaryExpression)
        {
            UnaryExpression unaryExpression = lambda.Body as UnaryExpression;
            memberExpression = unaryExpression.Operand as MemberExpression;
        }
        else
        {
            memberExpression = lambda.Body as MemberExpression;
        }
        ConstantExpression constantExpression = memberExpression.Expression as ConstantExpression;
        PropertyInfo propertyInfo = memberExpression.Member as PropertyInfo;


        // il faut remonter la hierarchie, car meme public, un event n est pas visible dans les enfants
        FieldInfo eventField;
        Type baseType = sender.GetType();
        do
        {
            eventField = baseType.GetField(INotifyPropertyChangedEventFieldName, BindingFlags.Instance | BindingFlags.NonPublic);
            baseType = baseType.BaseType;
        } while (eventField == null);

        // on a trouvé l'event, on peut invoquer tt les delegates liés
        MulticastDelegate eventDelegate = eventField.GetValue(sender) as MulticastDelegate;
        if (eventDelegate == null) return; // l'event n'est bindé à aucun delegate
        foreach (Delegate handler in eventDelegate.GetInvocationList())
        {
            handler.Method.Invoke(handler.Target, new Object[] { sender, new PropertyChangedEventArgs(propertyInfo.Name) });
        }
    }
champier
  • 11
  • 2
-3

Just Use this attribute above your automatic property declaration

[NotifyParentProperty(true)]
public object YourProperty { get; set; }
Amir
  • 770
  • 8
  • 21