What's the best way to call INotifyPropertyChanged's PropertyChanged event? [duplicate]
Asked Answered
L

3

10

When you implement the INotifyPropertyChanged interface, you're responsible for calling the PropertyChanged event each and everytime a property is updated in the class.

This typically leads to the following code :

    public class MyClass: INotifyPropertyChanged

        private bool myfield;
        public bool MyField
        {
            get { return myfield; }
            set
            {
                if (myfield == value)
                    return;
                myfield = value;
                OnPropertyChanged(new PropertyChangedEventArgs("MyField"));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler h = PropertyChanged;
            if (h != null)
                h(this, e);
        }
   }

That is 12 lines per property.

It would be so much simpler if one was able to decorate automatic properties like this :

[INotifyProperty]
public double MyField{ get; set; }

But unfortunately this is not possible (see this post on msdn for example)

How can I reduce the amount of code needed per property?

Lockman answered 28/1, 2009 at 17:39 Comment(4)
see #1329638 for a compiler checked way of implementing INotifyPropertyChanged. Avoiding having the property names as a magic string.Lucius
also, you can weave in the boilerplate code at run-time if you use an IoC container: #489087 (warning: this will warp your mind if unfamiliar with IoC)Heathheathberry
Just gonna add: PostSharp has support for this now.Hypoxia
A more recent (and highly popular) answer can be found here: #1316121Avunculate
T
7

Actually, it's only 3-4 lines per property; the other lines are amortized over all "notifying" properties:

class Person : INotifyPropertyChanged
{
    #region INotifyPropertyChanged: Shared bit
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, e);
    }
    #endregion

    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (_firstName == value)
                return;
            _firstName = value;
            OnPropertyChanged(new PropertyChangedEventArgs("FirstName"));
        }
    }

    // Ditto for other properties
}

You could try something like the following, which shares some more of the load:

private string _firstName;
public string FirstName
{
    get { return _firstName; }
    set { SetNotifyingProperty("FirstName", ref _firstName, value); }
}
private void SetNotifyingProperty<T>(string propertyName,
                                     ref T field, T value)
{
    if (value.Equals(field))
        return;
    field = value;
    OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
Thrilling answered 16/2, 2009 at 19:11 Comment(1)
Good idea. Btw, another problem with that code is that a new instance of PropertyChangedEventArgs is created each and every time a property changes. EventArgs could be stored in members variable for later use.Lockman
L
2

What I do for now is that I write this in my class :

 //AUTOGENERATE INotifyProperty
 private bool myfield;

And I wrote a small tool which generate all the needed property code in a partial class. This is by no way an elegant solution, but it works :)

Lockman answered 28/1, 2009 at 17:39 Comment(0)
C
1

It makes most sense to outsource.

Write a class ( ObservableObject) with the following code:

class ObservableObject : INotifyPropertyChanged
{
  public event PropertyChangedEventHandler PropertyChanged;

  protected void OnPropertyChanged(string name)
  {
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
  }
}

All classes derived from this class can access the method, thanks to protected.

Example:

class Example : ObservableObject
{
  //propfull
  private string name;
  public string Name
  {
    get {return name;}
    set 
    {
      name = value;
      OnPropertyChanged(nameof(Name));
    }
  }
}
Corroborate answered 16/8, 2019 at 12:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.