2

In wpf we often use following pattern for bindable properties:

private Foo _bar = new Foo();
public Foo Bar
{
    get { return _bar; }
    set
    {
        _bar = value;
        OnPropertyChanged();
    }
}

public void OnPropertyChanged([CallerMemberName] string property = "")
{
    if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs(property));
}

CallerMemberNameAttribute does nice magic, generating for us "Bar" parameter from setter name.

However, often there are properties without setter or dependent properties:

private Foo _bar;
public Foo Bar
{
    get { return _bar; }
    set
    {
        _bar = value;
        OnPropertyChanged();
    }
}

public bool IsBarNull
{
    get { return _bar == null; }
}

In given example, when Bar is changed then IsBarNull needs event too. We can add OnPropertyChanged("IsBarNull"); into Bar setters, but ... using string for properties is:

  • ugly;
  • hard to refactor (VS's "Rename" will not rename property name in string);
  • can be a source of all kind of mistakes.

WPF exists for so long. Is there no magical solution yet (similar to CallerMemberNameAttribute)?

Sinatr
  • 20,892
  • 15
  • 90
  • 319

3 Answers3

7

Use C# 6 and the nameof feature:

OnPropertyChange(nameof(IsBarNull));

That generates equivalent code to:

OnPropertyChange("IsBarNull");

... but without the fragility.

If you're stuck on earlier versions of C#, you can use expression trees for this, but I regard that as a bit of a hack and a potential performance issue (as the tree is recreated on each call). nameof doesn't require any library support, just a new compiler - so if you upgrade to VS 2015 (or later, dear readers from the future...) you should be fine.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Here it is a good example in C# 5 using lambda expressions. Unfortunately this is not an efficient solution, but encountered in applications. - http://stackoverflow.com/questions/7728465/implementing-notifypropertychanged-without-magic-strings – Pawel Maga Jul 17 '15 at 09:23
  • @PawelMaga: Which were you thinking of? I can't see any examples using reflection there. Are you thinking of expression trees? – Jon Skeet Jul 17 '15 at 09:25
  • Sees hot question. "Hey Jon Skeet's video showed me how to do that with C# 6!". Jon Skeet has already answered... – RubberDuck Jul 17 '15 at 09:53
1

if C# 6 is not at hand, here's some method i'm using quite often using Expressions:

public static class ExpressionExtensions
{
    public static string GetMemberName<T>(this Expression<Func<T, object>> expression)
    {
        return GetMemberName(expression.Body);
    }

    public static string GetMemberName (this Expression propertyExpression)
    {
        var lambda = propertyExpression as LambdaExpression;
        MemberExpression memberExpression = null;

        if (propertyExpression is UnaryExpression)
        {
            var unaryExpression = propertyExpression as UnaryExpression;
            memberExpression = unaryExpression.Operand as MemberExpression;
        }
        else if (lambda != null && lambda.Body is UnaryExpression)
        {
            var unaryExpression = lambda.Body as UnaryExpression;
            memberExpression = unaryExpression.Operand as MemberExpression;
        }
        else if (lambda != null)
        {
            memberExpression = lambda.Body as MemberExpression;
        }
        else
        {
            var expression = propertyExpression as MemberExpression;
            if (expression != null)
                memberExpression = expression;
        }

        if (memberExpression == null) return null;

        var propertyInfo = memberExpression.Member;

        return propertyInfo.Name;
    }
}

usage:

var propertyName = ExpressionExtensions.GetMemberName<DateTime>(item => item.Day);
0

DevExpress offers in it's BindableBase class a method SetProperty which reflects on the property you like to set:

private Foo _bar;
public Foo Bar
{
    get { return _bar; }
    set
    {
        SetProperty(ref _bar, value, () => Bar);
    }
}

It automatically looks for the correct property to update and only sends property changed events if necessary

DerApe
  • 3,097
  • 2
  • 35
  • 55