Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to let a parent class know about a change in its children?

This is an example code:

public class MyParent : INotifyPropertyChanged
{
    List<MyChild> MyChildren;

    public bool IsChanged
    {
        get
        {
            foreach (var child in MyChildren)
            {
                if (child.IsChanged) return true;
            }
            return false;
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;
    private void RaiseChanged(string propName)
    {
        if (PropertyChanged != null)
            PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
    }
}

public class MyChild : INotifyPropertyChanged
{
    private int _Value;
    public int Value
    {
        get
        {
            return _Value;
        }
        set
        {
            if (_Value == value)
                return;
            _Value = value;
            RaiseChanged("Value");
            RaiseChanged("IsChanged");
        }
    }
    private int _DefaultValue;
    public int DefaultValue
    {
        get
        {
            return _DefaultValue;
        }
        set
        {
            if (_DefaultValue == value)
                return;
            _DefaultValue = value;
            RaiseChanged("DefaultValue");
            RaiseChanged("IsChanged");
        }
    }

    public bool IsChanged
    {
        get
        {
            return (Value != DefaultValue);
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaiseChanged(string propName)
    {
        if (PropertyChanged != null)
            PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
    }
}

Let's say I now have two instances of my classes, one as myParent, and the other as myChild. I have two visual elements, that each have a property bound to the IsChnaged property of my instances; ElementA bound to myParent.IsChanged and ElementB bound to myChild.IsChanged.

When myChild.Value differs from its default value, the myChild.IsChanged is set to true and the ElementB is updated accordingly.

What I need is when either of the myParent children (which here is only one) have their IsChanged value set to true, its own (the parent's) IsChanged value be set to true and its corresponding element (ElementA here) be updated accordingly.

The myParent.IsChanged is only read once (when the binding is set) and it has no sense about its children changing. Where should i put the RaiseChanged("IsChanged") for MyParent? How can I let the parent know when its children have changed?

Thanks in advance

like image 528
iXed Avatar asked Jul 11 '11 12:07

iXed


1 Answers

INotifyPropertyChanged has already provided the mechanism for you: the PropertyChanged event. Just have the parent add a handler to its children's PropertyChanged, and then in that handler call RaiseChanged("IsChanged");

Also, you may want to put the INotifyPropertyChanged implementation in a base class, and have your (what appear to be) ViewModels inherit from that. Not required for this option, of course, but it will make the code a little cleaner.

Update: In the parent object:

// This list tracks the handlers, so you can
// remove them if you're no longer interested in receiving notifications.
//  It can be ommitted if you prefer.
List<EventHandler<PropertyChangedEventArgs>> changedHandlers =
    new List<EventHandler<PropertyChangedEventArgs>>();

// Call this method to add children to the parent
public void AddChild(MyChild newChild)
{
    // Omitted: error checking, and ensuring newChild isn't already in the list
    this.MyChildren.Add(newChild);
    EventHandler<PropertyChangedEventArgs> eh =
        new EventHandler<PropertyChangedEventArgs>(ChildChanged);
    newChild.PropertyChanged += eh;
    this.changedHandlers.Add(eh);
}

public void ChildChanged(object sender, PropertyChangedEventArgs e)
{
    MyChild child = sender as MyChild;
    if (this.MyChildren.Contains(child))
    {
        RaiseChanged("IsChanged");
    }
}

You don't actually have to add anything to the child class, since it is already raising the correct event when it changes.

like image 172
dlev Avatar answered Oct 11 '22 14:10

dlev