Изменено только событие после последнего источника данных TreeViewItem - PullRequest
0 голосов
/ 21 сентября 2018

У меня есть TreeView в моем View, который привязан к списку корневых Node s в моей ViewModel.У этих корней Node s может быть ребенок Nodes.Все узлы относятся к одному типу и имеют свойство IsSelected, которое связано со свойством IsChecked зависимости CheckBox, которое содержится в соответствующем TreeViewItem.Для 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 дочернего узла тоже.После распространения всех свойств я хочу запустить событие.Но только тогда, когда никакие дальнейшие узлы не будут изменены.Затем я хочу сделать что-то во ViewModel, что занимает некоторое время, поэтому было бы плохо с точки зрения производительности, если бы событие запускалось с каждым измененным свойством.

Поведение должно быть следующим:

  • Если для IsSelected узла установлено значение true или null, для IsSelected родительского узла устанавливается значение null, если не для всех IsSelected дочернего элемента узла установлено значение trueили null (что затем распространяется по дереву).
  • Если для IsSelected узла установлено значение true или null, для IsSelected родительского узла устанавливается значение true, если всеIsSelected родного брата узла установлены в true или null (что затем распространяется вверх по дереву).
  • Если IsSelected узла получает значение false, все его непосредственные дочерние элементыIsSelected узла также устанавливают на false (что затем распространяется вниз по дереву).
  • Узел, установленный на null, означает, что не все его непосредственные дочерние узлы были выбраны.

Итак, как мне добиться запуска события PropertyChanged (или другого, который я бы реализовал) только в кормовой части?последний узел был изменен?

1 Ответ

0 голосов
/ 01 октября 2018

Я закончил тем, что сделал Александру .

Я представил два события IsSelectedChangedPropagationStarted & 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);
    }
}

Реализуя custom EventArgs, я также мог бы сказать слушателям, изменилось ли что-то вообще, чтобы они могли действовать соответственно.

...