繁体   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