zuzuyiru
zuzuyiru

Reputation: 41

Minimizing WPF boilerplate code on bound properties

Consider a WPF dialogue with lots of input fields, which are bound to properties in a view-model. E.g.

...
<TextBox Text="{Binding FirstName}">
...

public string FirstName {
  get { return mFirstName; }
  set {
    if (mFirstName == value) return;
    mFirstName = value;
    OnPropertyChanged("FirstName");
  }
}

As there are tens of fields like this, I would like to minimize the boilerplate C# code to be written. What options do I have?

Upvotes: 4

Views: 771

Answers (4)

Petter Hesselberg
Petter Hesselberg

Reputation: 5518

If you have the option of using a base class, consider inheriting view model objects from something like this:

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

    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Equals(storage, value))
        {
            return false;
        }

        storage = value;

        // ReSharper disable once ExplicitCallerInfoArgument
        OnPropertyChanged(propertyName);
        return true;
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected void OnPropertiesChanged(params string[] propertyNames)
    {
        foreach (string propertyName in propertyNames)
        {
            // ReSharper disable once ExplicitCallerInfoArgument
            OnPropertyChanged(propertyName);
        }
    }
}

Example usage, showing that the boilerplate is greatly reduced:

public sealed class ViewModel : BindableBase
{
    private string name;

    public string Name
    {
        get { return name; }
        private set { SetProperty(ref name, value); }
    }
}

(If you can't use a base class (e.g., you already have one or are using properties on framework elements), you still have the option of adding similar support directly in the class in question.)

Upvotes: 2

Piotr Falkowski
Piotr Falkowski

Reputation: 1967

First, as I guess you already use Microsoft.Prism, you can drop the string and profit from CallerMemberNameAttribute behind the scenes for you, so that your code would look like this:

public string FirstName {
  get { return mFirstName; }
  set {
    if (mFirstName == value) return;
    mFirstName = value;
    OnPropertyChanged();
  }
}

This is also equivalent to c# 6.0 nameof(FirstName) operator.

Second, you can dig into AOP and abstract the boilerplate to an attribute. One of the AOP frameworks that deals with this is PostSharp and using it your code could look like this:

[NotifyPropertyChanged]
public class Customer
{
    public string FirstName { get; set; }

Though it's not free, and AOP has it's drawbacks (thanks Evk).

Similar questions have been asked 1,2, and there does not seem to be optimal answer right now sadly, as it's everyones pain.

Upvotes: 0

Max Hampton
Max Hampton

Reputation: 1304

I use Fody to inject property changed code at compile time. Your class gets an [ImplementPropertyChanged] attribute, then your { get; set; } properties become notifying properties in the compiled code.

https://github.com/Fody/PropertyChanged

Upvotes: 0

Rachael Dawn
Rachael Dawn

Reputation: 889

I can make your code a little easier to transform into a snippet.

if (mFirstName != value) {
    mFirstName = value;
    OnPropertyChanged("FirstName");
}

If just the time taken to write it is a pain, and you're using WPF a lot, snippets may also be of use. I know in Sublime Text, VS Code, and Visual Studio, Snippets can be invaluable. Otherwise, I think it's as bare bones as you can get, unless there's something I am not seeing

Upvotes: 0

Related Questions