I have a TreeView in my View that is databound to a list of root Node
s in my ViewModel. Those root Node
s can have child Nodes
. All nodes are of the same type and have the property IsSelected
that is bound to the IsChecked
dependency property of a CheckBox
that's contained in the respective TreeViewItem
. That CheckBox
has set IsThreeState
to false
.
public class Node : PropertyChangedBase, INode
{
private bool? _isSelected;
private IList<INode> _nodes;
private INode _parent;
public Node()
{ }
public bool? IsSelected
{
get { return _isSelected; }
set
{
if (_SetField(ref _isSelected, value))
{
_OnIsSelectedChanged();
}
}
}
public IList<INode> Nodes
{
get { return _nodes; }
set { _SetField(ref _nodes, value); }
}
public INode Parent
{
get { return _parent; }
set { _SetField(ref _parent, value); }
}
private void _OnIsSelectedChanged()
{
if (IsSelected.HasValue)
{
if (IsSelected.Value)
{
if (Parent != null)
{
// Set IsSelected on all parenting nodes to:
// - true, if all of their immediate child packages have been selected
// - null, else
}
if (Nodes != null && Nodes.Count > 0)
{
// Prevent running this method again by circumventing setting the property
_SetField(ref _isSelected, null);
}
}
else
{
if (Parent != null)
{
// Set IsSelected of the parent to null
}
if (Nodes != null)
{
// Set IsSelected = false on all child nodes
}
}
}
else if (Parent != null)
{
// Set IsSelected on all parenting nodes to:
// - true, if all of their immediate child packages have been selected
// - null, else
}
}
}
PropertyChangedBase
is a base class implementing INotifyPropertyChanged
. It's been designed after this SO answer. If the set value actually changes, _SetField(ref object, object)
returns true
and notifies about the property change.
If the user clicks a CheckBox, that change should propagate the parent node's (up to the root node) IsSelected
property and to the child node's IsSelected
property, too. After the propagation of all Properties finished, I want to fire an event. But only when no further node will be changed. I then want to do something in the ViewModel, that takes some time, so it would be bad performance-wise if the event would fire with each changed property.
The behaviour should be the following:
- If a node's
IsSelected
gets set totrue
ornull
, the parent node'sIsSelected
gets set tonull
if not all of the node's sibling'sIsSelected
are set totrue
ornull
(what then propagates up the tree). - If a node's
IsSelected
gets set totrue
ornull
, the parent node'sIsSelected
gets set totrue
if all of the node's sibling'sIsSelected
are set totrue
ornull
(what then propagates up the tree). - If a node's
IsSelected
gets set tofalse
, all of its immediate child node'sIsSelected
get set tofalse
, too (what then propagates down the tree). - A node set to
null
means that not all of its immediate child nodes have been selected.
So how can I achieve firing the PropertyChanged event (or another I'd implement) only after the last node has been changed?