Click here to Skip to main content
15,881,248 members
Articles / Desktop Programming / WPF
Tip/Trick

Concise PropertyChanged Implementation

Rate me:
Please Sign up or sign in to vote.
4.25/5 (7 votes)
29 Jun 2016CPOL1 min read 17.9K   11   16
Save wear and tear on your keyboard: INotifyPropertyChanged with the fewest key-strokes.

I H8 PropertyChanged

...because I got used to auto-properties really quickly...

The most painful part of building entities to interact with the UI, (for me at least) is having to create properties that participate in the INotifyPropertyChanged interface.

You know the ones I mean:

C#
string _backingField;

public string MyProperty  
{
    get { return _backingField; }
    set 
    { 
          if (!string.Equals(value, _backingField)
          {
              _backingField = value;
              OnPropertyChanged("MyProperty");
          }
    }
}

You can improve the rate at which you can add these using a code-snippet, but there are annoying limitations, like having to rename the backing field to match the naming convention, the problem of the name being passed to OnPropertyChanged becoming out-of-date with refactoring *(unless you are using C#6.0/VS2015 and "nameof()") and that it's too verbose, you end up with a bunch of backing fields you don't want, and it's just fugly.

Wouldn't it be nicer if it looked like this?

C#
public string MyProperty
{
    get { return GetValue(() => MyProperty); }
    set { SetValue(() => MyProperty, value); }
}

The above code can be generated easily enough with a snippet, it neatly aligns, requires no backing field, type-inference and generics work together to make it strongly-typed, and refactoring the property-name will not break anything.

What's the Trick?

Expressions! The GetValue and SetValue method's first parameter is an Expression<Func<T>> - this allows you to pass a lambda expression into the method (with the property name) and supplies the generic-type context (T)

The rest of the trick is that the backing field is in fact a Dictionary<string, object> that stores the values for all the properties.

C#
/// <summary>
/// stores the values for the properties
/// </summary>
protected Dictionary<string, object> m_values = new Dictionary<string, object>();

/// <summary>
/// gets the value of the member specified in the member expression.
/// Generic type parameters should be inferred.
/// </summary>
/// <typeparam name="T">the property type</typeparam>
/// <param name="memberExpression">lambda expression
/// referring to the property invoking this method</param>
/// <returns>the value, or default(T)</returns>
public T GetValue<T>(Expression<Func<T>> memberExpression)
{
    var body = memberExpression.Body as MemberExpression;
    if (body != null)
    {
        object value;
        if (m_values.TryGetValue(body.Member.Name, out value))
        {
            // return the value;
            return (T)value;
        }
    }

    // return a default:
    return default(T);
}

/// <summary>
/// sets the value
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="memberExpression"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool SetValue<T>(Expression<Func<T>> memberExpression, T value)
{
    // is the value different from the existing?
    if (EqualityComparer<T>.Default.Equals(value, GetValue(memberExpression)))
    {
        return false;
    }

    // fetch the name of the property:
    var body = memberExpression.Body as MemberExpression;
    if (body != null)
    {
        // set the value:
        m_values[body.Member.Name] = value;

        // raise the property-changed event
        OnPropertyChanged(body.Member.Name);
    }

    // return true for changed:
    return true;
}

License

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


Written By
Software Developer (Senior) Decipha
Australia Australia
Wrote his first computer game in Microsoft Basic, on a Dragon 32 at age 7. It wasn't very good.
Has been working as a consultant and developer for the last 15 years,
Discovered C# shortly after it was created, and hasn't looked back.
Feels weird talking about himself in the third person.

Comments and Discussions

 
QuestionThread safety and performance Pin
tom-englert1-Jul-16 2:51
tom-englert1-Jul-16 2:51 
AnswerRe: Thread safety and performance Pin
georani1-Jul-16 6:19
georani1-Jul-16 6:19 
GeneralRe: Thread safety and performance Pin
Simon Bridge1-Jul-16 12:51
Simon Bridge1-Jul-16 12:51 
GeneralRe: Thread safety and performance Pin
georani1-Jul-16 14:18
georani1-Jul-16 14:18 
GeneralRe: Thread safety and performance Pin
Simon Bridge3-Jul-16 14:27
Simon Bridge3-Jul-16 14:27 
GeneralRe: Thread safety and performance Pin
georani4-Jul-16 3:08
georani4-Jul-16 3:08 
GeneralRe: Thread safety and performance Pin
Simon Bridge4-Jul-16 14:46
Simon Bridge4-Jul-16 14:46 
AnswerRe: Thread safety and performance Pin
hooodaticus1-Jul-16 7:04
hooodaticus1-Jul-16 7:04 
GeneralRe: Thread safety and performance Pin
tom-englert1-Jul-16 20:46
tom-englert1-Jul-16 20:46 
GeneralRe: Thread safety and performance Pin
Simon Bridge3-Jul-16 14:37
Simon Bridge3-Jul-16 14:37 
GeneralRe: Thread safety and performance Pin
hooodaticus7-Sep-16 10:22
hooodaticus7-Sep-16 10:22 
AnswerRe: Thread safety and performance Pin
Simon Bridge1-Jul-16 12:47
Simon Bridge1-Jul-16 12:47 
AnswerRe: Thread safety and performance Pin
Simon Bridge3-Jul-16 16:43
Simon Bridge3-Jul-16 16:43 
SuggestionGreat Pin
Kim Nordmo30-Jun-16 4:40
Kim Nordmo30-Jun-16 4:40 
QuestionGreat! Pin
Aladár Horváth29-Jun-16 21:06
professionalAladár Horváth29-Jun-16 21:06 
AnswerRe: Great! Pin
Simon Bridge30-Jun-16 14:36
Simon Bridge30-Jun-16 14:36 
On my Dev machine, (which is fairly powerful but not a monster) resolution of property values when debugging occurs in less than 1 ms, but I haven't done any actual performance tests. The slowest part would be the dictionary access, and the algorithm for finding dictionary entries is extremely efficient, even with hundreds of thousands of entries it still resolves in <1 ms, so the dozen or so properties on a ViewModel aren't an issue.

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.