[英]Only fire event after last TreeViewItem datasource has changed
我的View中有一个TreeView,它绑定到ViewModel中的根Node
列表。 这些根Node
S能有子Nodes
。 所有节点的类型相同,并具有IsSelected
属性,该属性绑定到相应TreeViewItem
包含的CheckBox
的IsChecked
依赖项属性。 CheckBox
已将IsThreeState
设置为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
是实现INotifyPropertyChanged
的基类。 它是根据此SO答案设计的。 如果设置值实际发生更改,则_SetField(ref object, object)
返回true
并通知属性更改。
如果用户单击CheckBox,则所做的更改也应将父节点的IsSelected
属性(直到根节点) IsSelected
到子节点的IsSelected
属性。 所有属性的传播完成后,我要触发一个事件。 但是仅当没有其他节点将被更改时。 然后,我想在ViewModel中做一些事情,这会花费一些时间,因此如果事件随每个更改的属性一起触发,则将导致性能下降。
该行为应为以下情况:
IsSelected
被设置为true
或null
,父节点的IsSelected
获取设置为null
,如果不是所有节点的兄弟姐妹的的IsSelected
被设置为true
或null
(那么什么传播了树)。 IsSelected
设置为true
或null
,则如果节点的所有同级节点的IsSelected
都设置为true
或null
(然后沿树传播),则父节点的IsSelected
设置为true
。 IsSelected
设置为false
,则其所有直接子节点的IsSelected
设置为false
(然后沿树传播)。 null
的节点意味着并非所有其直接子节点都已被选择。 那么,如何仅在更改了最后一个节点之后才能实现触发PropertyChanged事件(或我实现的另一个事件)?
我最终按照亚历山大的建议做了。
我介绍了两个事件IsSelectedChangedPropagationStarted
和IsSelectedChangedPropagationCompleted
,第一个事件在处理选择之前IsSelectedChangedPropagationCompleted
,第二个事件在完成选择时引发。 该类现在看起来与此类似:
public class Node : PropertyChangedBase, INode
{
// #### Attributes
private bool? _isSelected;
private IList<INode> _nodes;
private INode _parent;
// #### Constructor
public Node()
{ }
// #### Properties
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); }
}
// #### Events
public event EventHandler IsSelectedChangedPropagationStarted;
public event EventHandler IsSelectedChangedPropagationCompleted;
// #### Instance Methods
private void _OnIsSelectedChanged()
{
IsSelectedChangedPropagationStarted?.Invoke(this, EventArgs.Empty);
if (IsSelected.HasValue)
{
if (IsSelected.Value)
{
RecursivelySetAllParents();
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
}
RecursivelySetAllChildren();
}
}
else if (Parent != null)
{
// Set IsSelected on all parenting nodes to:
// - true, if all of their immediate child packages have been selected
// - null, else
}
IsSelectedChangedPropagationCompleted?.Invoke(this, EventArgs.Empty);
}
}
通过实现自定义EventArgs
我还可以告诉侦听器是否有任何更改,以便他们可以采取相应的措施。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.