7
\$\begingroup\$

Every time I go to write an MVVM application (say every 4-6 months) I rewrite my ViewModelBase class. This is for a range of reasons but let's say either I don't have access to prior code, the previous code was built for a client and isn't my code, or I'm working on someone else's machine and still don't have the code.

So I rewrite the basic INotifyPropertyChanged implementation, and I think it's a little different each time. Here's what I've come up with today:

public class ViewModelBase : INotifyPropertyChanged
{
    protected void OnPropertyChanged<T>(Expression<Func<T>> expression)
    {
        var property = (MemberExpression)expression.Body;
        this.OnPropertyChanged(property.Member.Name);
    }

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

I would like to get a nice implementation that is simple and small, and any improvements to this (what other functionality is required in a ViewModelBase?) would be great.

\$\endgroup\$
  • \$\begingroup\$ I've never considered doing this. I'm interested to see what context would this be useful when using the view model on the view? Do you have any example code of it's usage? \$\endgroup\$ – dreza Jul 19 '12 at 10:19
  • 1
    \$\begingroup\$ @dreza Which part in particular? Implementing the INotifiyPropertyChanged interface is basic functionality that a ViewModel needs to provide, and I'm just sharing that across my ViewModels... \$\endgroup\$ – Kirk Broadhurst Jul 24 '12 at 2:06
  • \$\begingroup\$ Yeah, I understand the functionality. I was interested to see in what context it was used as it it's my understanding that every view model does not need to provide the functionality. However I've done a bit of googling about it anyway cheers. \$\endgroup\$ – dreza Jul 24 '12 at 20:47
7
\$\begingroup\$

I've used the below for a while:

public abstract class PropertyChangedBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        var propertyChanged = this.PropertyChanged;

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

    protected bool SetProperty<T>(ref T backingField, T Value, Expression<Func<T>> propertyExpression)
    {
        var changed = !EqualityComparer<T>.Default.Equals(backingField, Value);

        if (changed)
        {
            backingField = Value;
            this.RaisePropertyChanged(ExtractPropertyName(propertyExpression));
        }

        return changed;
    }

    private static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
    {
        var memberExp = propertyExpression.Body as MemberExpression;

        if (memberExp == null)
        {
            throw new ArgumentException("Expression must be a MemberExpression.", "propertyExpression");
        }

        return memberExp.Member.Name;
    }
}

I can write my properties like this:

    private int id;

    public int Id
    {
        get
        {
            return this.id;
        }

        set
        {
            this.SetProperty(ref this.id, value, () => this.Id);
        }
    }
\$\endgroup\$
1
\$\begingroup\$

Specifically related to NotifyPropertyChanged I've found VerifyPropertyName to be useful.

From Josh Smith's site: A base class which implements INotifyPropertyChanged

[Conditional("DEBUG"), DebuggerStepThrough()]
public void VerifyPropertyName(string propertyName)
{
// Verify that the property name matches a real,  
// public, instance property on this object.
if (TypeDescriptor.GetProperties(this)(propertyName) == null) {
    string msg = "Invalid property name: " + propertyName;

    if (this.ThrowOnInvalidPropertyName) {
        throw new Exception(msg);
    } else {
        Debug.Fail(msg);
    }
}
}
\$\endgroup\$
1
\$\begingroup\$

This is many years later, but anyone stumbling upon this now should be aware of MVVM Light and PropertyChanged.Fody

Both are on nuget.org

\$\endgroup\$
1
\$\begingroup\$
protected void OnPropertyChanged<T>(Expression<Func<T>> expression)
{
    var property = (MemberExpression)expression.Body;
    this.OnPropertyChanged(property.Member.Name);
}
  • Expression<Func<T>> is a pretty expensive allocation, usually not a problem but good to know. Used BenchmarkDotNet and ran a benchmark for fun, here are the results:
                      Method |        Median |     StdDev | Scaled |
    ------------------------ |-------------- |----------- |------- |
     SetWithCallerMemberName |     2.5169 ns |  0.3584 ns |   1.00 |
           SetWithExpression | 1,343.9223 ns | 38.2650 ns | 533.97 |
  • Adding some more validation may make sense. Maybe a debug assert checking that there is a property named property.Member.Name?
  • If you are using C#6 and this overload should be removed. Use nameof instead.
protected void OnPropertyChanged(string name)
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(name));
    }
}
  • Good that you copy to a temp before nullchecking.
  • Depending on C# version [CallerMemberName] should be added like so:

    protected void OnPropertyChanged([CallerMemberName] string name = null)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.