[英]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.