Christopher Trevor Christopher Trevor - 2 months ago 21
C# Question

Preventing infinite loops when using INotifyPropertyChanged with a WPF treeview containing checkboxes

This is my first question so I apologise if it is not formatted perfectly.

I am new to WPF and MVVM and I have run into an issue I can't seem to figure out.

I have a treeview that displays a MenuItem hierarchy with a checkbox per MenuItem, both for Parent and Child nodes. The solution current allows a user to click on a parent node and all child items are checked / unchecked as required.

I now need to implement the reverse of this, where if a user clicks on one of the child nodes the parent node should be selected if it is not already selected.

The problem I currently have is that checking the parent node programmatically fires the INotifiedPropertyChanged event for the parent node which rechecks my child nodes.

How do I prevent this from happening?

Here is my MenuItem code:

public class MenuItem : INotifyPropertyChanged
{
string _name;
List<MenuItem> _subItems = new List<MenuItem>();
bool _isChecked;
MenuItem _parent;

public List<MenuItem> SubItems
{
get { return _subItems; }
set
{
_subItems = value;
RaisePropertyChanged("SubItems");
}
}

public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged("Name");
}
}

public bool IsChecked
{
get { return _isChecked; }
set
{
_isChecked = value;
RaisePropertyChanged("IsChecked");
}
}

public MenuItem Parent
{
get { return _parent; }
set
{
_parent = value;
RaisePropertyChanged("Parent");
}
}

public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

if (propertyName == "IsChecked")
{
if (Parent == null)
{
foreach (MenuItem Child in _subItems)
Child.IsChecked = this.IsChecked;
}

//if (Parent != null)
//{
// Parent.IsChecked = IsChecked ? true :Parent.IsChecked;
//}
}
}
}


The commented code above is where I am encountering the error.

Any guidance will be greatly appreciated.

Answer

Just a bit more elaborated answer based on the one already written by OP

    public bool IsChecked
    {
        get { return _isChecked; }
        set
        {
            _isChecked = value;

            if (_parent == null)
            {
                foreach (MenuItem Child in _subItems)
                {
                    Child._isChecked = this._isChecked;
                    Child.RaisePropertyChanged("IsChecked");
                }
            }

            if (_parent != null)
            {
                _parent.NotifyChecked(_isChecked);
            }

            RaisePropertyChanged("IsChecked");
        }
    }
    public void NotifyChecked(bool childChecked) 
    { 
       _isChecked = childChecked;
        RaisePropertyChanged("IsChecked"); 
       if (_parent != null)
       {
           _parent.NotifyChecked(_isChecked);
       }
    }
Comments