4

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?

zuzuyiru
  • 41
  • 1
  • Passing the name isn't needed, use void OnPropertyChanged ( [CallerMemberName] String propertyName = null ). Imo there are frameworks which solve the rest of the boilerplate with attributes but it's been a while ago I looked into to it. Another option is having something like a Dictionary wrapper with generic code for getting/setting any value (also with the CallerMemberName trick) and raising the event. Then you just have for example `get{ return props.Get() }` and `set{ props.Set(value); }` – stijn Nov 16 '16 at 13:39
  • You can also use proper tools, like Resharper, which can generate that boilerplate code for you (or at least make it much easier). – Evk Nov 16 '16 at 13:40

4 Answers4

2

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.)

Petter Hesselberg
  • 5,062
  • 2
  • 24
  • 42
0

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

Rachael Dawn
  • 819
  • 6
  • 13
0

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.

Community
  • 1
  • 1
Piotr Falkowski
  • 1,957
  • 2
  • 16
  • 24
  • AOP tools (at least in .NET) usually do not use reflection - they rewrite your assembly IL code directly (so really modifying your methods\classes and so on). – Evk Nov 16 '16 at 13:50
0

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

Max Hampton
  • 1,254
  • 9
  • 20