簡體   English   中英

最后一個TreeViewItem數據源更改后的僅觸發事件

[英]Only fire event after last TreeViewItem datasource has changed

我的View中有一個TreeView,它綁定到ViewModel中的根Node列表。 這些根Node S能有子Nodes 所有節點的類型相同,並具有IsSelected屬性,該屬性綁定到相應TreeViewItem包含的CheckBoxIsChecked依賴項屬性。 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被設置為truenull ,父節點的IsSelected獲取設置為null ,如果不是所有節點的兄弟姐妹的的IsSelected被設置為truenull (那么什么傳播了樹)。
  • 如果節點的IsSelected設置為truenull ,則如果節點的所有同級節點的IsSelected都設置為truenull (然后沿樹傳播),則父節點的IsSelected設置為true
  • 如果節點的IsSelected設置為false ,則其所有直接子節點的IsSelected設置為false (然后沿樹傳播)。
  • 設置為null的節點意味着並非所有其直接子節點都已被選擇。

那么,如何僅在更改了最后一個節點之后才能實現觸發PropertyChanged事件(或我實現的另一個事件)?

我最終按照亞歷山大的建議做了。

我介紹了兩個事件IsSelectedChangedPropagationStartedIsSelectedChangedPropagationCompleted ,第一個事件在處理選擇之前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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM