Bubbling INotifyPropertyChanged and Nested Properties

If I have the following layout:


public class A : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public B { get; set; }
}

public class B { public C { get; set; } }
public class C { public D { get; set; } }
public class D { public E { get; set; } }

//... add n classes

public class Z
{
    public int Property
    {
        set
        {
            if(PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("Property"));
        }
    }
}

What is the cleanest way for me to notify A when ABCDE .. Z.Property changes?

When something inside A changes, I want it to be marked as dirty, so I can tell the system that A needs to be saved.

+3
source share
3 answers

I have been working on the same problem recently. My approach was to simply enable B, C, D, etc. Manage your own dirty state and then modify property A IsDirtyas such:

public bool IsDirty
{
   get
   {
        return _isDirty || B.IsDirty || C.IsDirty /* etc */;
   }
}

For me it is not easy, but it makes sense. A is dirty if any of its properties have been changed, and B, C, D, etc. - all properties of A.

+1

, . , , , PropertyChanged. (VoidHandler).

public delegate void VoidHandler(object sender);

public class B // also C,D,E,...
{
  // A.ItemChanged() will be wired to this SomethingChangedHandler.
  // I heard you are saving. Exclude SomethingChangedHandler from save.
  [field: NonSerialized]
  public VoidHandler SomethingChangedHandler;

  private c;
  public C
  {
    set
    {
      // unwire handler from old instance of C
      if(c != null)
        c.SomethingChangedHandler -= ItemChanged;

      // wire handler to new instance of C
      value.SomethingChangedHandler += ItemChanged;

      c = value;

      // setting c is also change which require notification
      ItemChanged(this);
    }
    get{}
  }

  // notify A about any change in B or in C
  void ItemChanged(object sender)
  {
    if(SomethingChangedHandler != null)
      SomethingChangedHandler(this);
  }
}
+1

-, ,

INotifyPropertyChanged - ?

"".

 public bool HasAlteredState { get; protected set; }

 public event PropertyChangedEventHandler PropertyChanged;

 private void propertyObject_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.OnPropertyChanged(e.PropertyName);
        }

 protected virtual void RegisterSubPropertyForChangeTracking(INotifyPropertyChanged propertyObject)
        {
            propertyObject.PropertyChanged += new PropertyChangedEventHandler(propertyObject_PropertyChanged);
        }

 protected virtual void DeregisterSubPropertyForChangeTracking(INotifyPropertyChanged propertyObject)
        {
            propertyObject.PropertyChanged -= propertyObject_PropertyChanged;
        }

  protected virtual void OnPropertyChanged(string propertyName)
    {
        this.HasAlteredState = true;
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
    {
        if (selectorExpression == null)
            throw new ArgumentNullException("selectorExpression");
        MemberExpression body = selectorExpression.Body as MemberExpression;
        if (body == null)
            throw new ArgumentException("The body must be a member expression");
        OnPropertyChanged(body.Member.Name);
    }

    protected bool SetField<T>(ref T field, T value, Expression<Func<T>> selectorExpression)
    {
         if (EqualityComparer<T>.Default.Equals(field, value)) return false;

        if (field is INotifyPropertyChanged)
        {
            if (field != null) { this.DeregisterSubPropertyForChangeTracking((INotifyPropertyChanged)field); }
        }
        if (value is INotifyPropertyChanged)
        {
            if (value != null) { this.RegisterSubPropertyForChangeTracking((INotifyPropertyChanged)value); }
        }

        field = value;
        OnPropertyChanged(selectorExpression);
        return true;
    }

private IndividualName _name;
public IndividualName PersonName
        {
            get { return _name; }
            set { SetField(ref _name, value, () => PersonName); }
        }

  • "" INotifyPropertyChanged
  • , , "" . , .

... 20% , . , , , , , : , .

  • , .
  • SetField; SetNotifyField , INotifyPropertyChanged ( ), SetField .

    if ( INotifyPropertyChanged)...

+1

Source: https://habr.com/ru/post/1796383/


All Articles