Иерархические уведомления об изменениях в иерархии объектов

У меня есть рекурсивная иерархия трех типов объектов в библиотеке C#. Давайте назовем их Ящиками, Гайками и Болтами. Коробки могут содержать другие коробки или гайки и болты. Гайки и болты, очевидно, не могут содержать ничего.

Давайте предположим, что в каждом боксе есть ObservableCollections of Box, Nut и Bolt. Каждый Гайка и Болт реализуют INotifyPropertyChanged.

Существует ли общепринятая лучшая практика для распространения уведомлений об изменениях в наблюдаемых коллекциях или изменениях свойств на любой гайке или болте для объекта, который содержит ссылку на самый верхний блок? Или какие-то конкретные шаблоны дизайна вы бы порекомендовали?

РЕДАКТИРОВАТЬ: чтобы дать некоторое представление об этой проблеме, я возглавляю проект Chemistry for Word. Вы можете увидеть компонент, который отображает структуры в режиме реального времени слева. Теперь, хотите верьте, хотите нет, но в настоящее время все обращается через привязку данных. Каждая из этих молекул, отображаемая на LHS, представляет собой ItemsControl. (И да, я использую WPF с MVVM!) Это оказалось слишком много накладных расходов и отсутствие гибкости для долгосрочного решения. Итак, я вернулся к созданию DrawingVisuals напрямую. Такой подход позволяет гораздо более точный контроль. Коробки, гайки и болты в моем первоначальном примере - это молекулы, атомы и связи. Если какие-либо из них будут добавлены, удалены или изменены, то дисплей должен знать об этом, чтобы он мог обновляться. Поскольку я уже реализовал интерфейсы и объекты для привязки данных, я хочу использовать код, который у меня уже есть.

3 ответа

Решение

У меня была похожая модель с быстрым доступом к восходящему потоку Node экземпляры в ориентированных ациклических графах. Node имеет слабую ссылку на своего непосредственного родителя. Node имеет свойство для получения Root..., которое пытается вернуть Root своего родителя. Если нет родителя, то этот узел является корнем. Корень основывается исключительно на сдерживании. Обратите внимание, что родительский элемент не является коллекцией... потому что иногда дочерний узел отсутствует даже в коллекции. Что-то более или менее как...

public abstract class Node
{
  WeakReference<Node> parent;

  public Node Root
  {
    get { return Parent?.Root ?? this; }
  }

  public Node Parent
  {
    get
    {
      if ( parent != null )
      {
        if ( parent.TryGetTarget( out Node parentNode ) )
        {
          return parentNode;
        }
      }
      return this;
    }
    internal set { /*...*/ } //--> if you're brave...
  }
}

Редактировать:

Что касается WeakReferences... одна из вещей, которые могут иметь наши графы, это ссылки на узлы в других графах. У нас есть служба распознавания узлов, которая будет извлекать эти другие узлы. Эти внешние ссылки представлены значением идентичности (а GUID или Long) и связанная слабая ссылка. Таким образом, мы можем загрузить указанный узел по мере необходимости, но не хранить его дольше, чем необходимо. Средство распознавания поддерживает кэш LRU узлов, разрешенных таким образом.

Если такая разрешенная ссылка должна разрешать своего родителя, существует аналогичный механизм, позволяющий зависимому узлу разрешать своего родителя. Даже собранные дочерние узлы узла могут быть лениво загружены через службу распознавания (хотя есть аннотации, которые информируют нашу платформу, когда выполнять отложенную загрузку, а когда нет).

Таким образом, слабые ссылки помогают со всеми этими случайно разрешенными сценариями. Эээ... точнее, они помогают нам не испортить сборку мусора в таких сценариях.

В некоторых аналитических сценариях у нас будут появляться сотни тысяч узлов. Я мог представить аналогичную динамику в химическом моделировании.

Почему бы вам не позвонить родителю в уведомлении об изменении. Что-то вроде следующего псевдокода:

Bolt()
{
    NotifyPropertyChanged(property)
    {
         PropertyChanged(this, property);
    }

    ChildNutPropertyChanged(Nut child, property)
    {
         PropertyChanged(this, child + property);
    }
}


Nut(Bolt parentBolt)
{ 
    parent = parentBolt;

    NotifyPropertyChanged(property)
    {
         PropertyChanged(this, property);
         parent.NotifyPropertyChanged(this, property);
    }
}

Если вы заключите в капсулу свой ObservableCollection гайки и болты и только сделать ReadOnlyObservableCollection общественности, вы могли бы сделать Add(Nut nut) метод (и еще один для болтов), который регистрируется в добавленной гайки NotifyPropertyChanged событие.

Таким образом, вы узнаете в Box когда свойство ребенка изменилось и принять меры.

Другие вопросы по тегам