0

Я пытаюсь понять, как можно объединить х количество событий ObservableCollections.CollectionChanged, выставленных как дерево объектов глубины уровня N на одно родительский уровень. Событие CollectionChanged, которое могут слушать пользователи? По сути, я хочу, чтобы воронка или пузырь всех дочерних событий CollectionChanged до самого верхнего родителя. Ряд решений, которые я заметил, что решение подобных проблем делает предположение о фиксированном количестве уровней, скажем, 2 глубины. Я хочу поддерживать любой уровень глубины.Chain CollectionChanged Events

Первоначально я надеялся, что могу просто передать экземпляр FieldInfos дочерним конструкторам и подключиться непосредственно к обработчику. Однако я получаю сообщение об ошибке с указанием «Событие„CollectionChanged“может появиться только на левой стороне + = или -. =

Спасибо,

public class FieldInfos 
    { 
     public event NotifyCollectionChangedEventHandler CollectionChanged; 

     private ObservableCollection<Field> _fields; 

     public ObservableCollection<Field> Fields => _fields ?? (_fields = new ObservableCollection<Field>()); 
    } 



    public class Field 
    { 
     public string Name; 

     private ObservableCollection<FieldInstance> _instances; 
     public ObservableCollection<FieldInstance> Instances => _instances ?? (_instances = new ObservableCollection<FieldInstance>()); 
    } 

    public class FieldInstance 
    { 
     public string Id { get; set; } 
    } 
+0

Чтобы сделать это, вам необходимо изменить 'ObservableCollection <>'. В противном случае вы можете создать шаблон фасада, чтобы сделать это - эффективно вы создали бы свой собственный класс «NestedObservableCollection <>», который обертывает внутренний 'ObservableCollection <>'. – Enigmativity

+0

Не могли бы вы предоставить пример кода, который иллюстрирует, что вы предлагаете в качестве возможного решения? – Mike

+1

@ Майк вы попробовали? – Asti

ответ

1

Самый простой подход подклассы оригинальный ObservableCollection<T>

.

Вы должны были бы, по крайней мере, один интерфейс, чтобы избежать проблем ковариации. Вы также можете иметь свои собственные классы для реализации интерфейса INotifyDescendantsChanged.

public interface INotifyDescendantsChanged 
{ 
    event NotifyCollectionChangedEventHandler DescendantsChanged; 
} 

public class ObservableBubbleCollection<T> : ObservableCollection<T>, INotifyDescendantsChanged 
{ 
    public event NotifyCollectionChangedEventHandler DescendantsChanged; 
    protected virtual void OnDescendantsChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     NotifyCollectionChangedEventHandler handler = DescendantsChanged; 
     if (handler != null) 
      handler(sender, e); 
    } 

    private readonly Func<T, INotifyDescendantsChanged> childSelector; 
    public ObservableBubbleCollection() { } 
    public ObservableBubbleCollection(Func<T, INotifyDescendantsChanged> childSelector) 
    { 
     this.childSelector = childSelector; 
    } 

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     base.OnCollectionChanged(e); 
     OnDescendantsChanged(this, e); 

     if (childSelector == null) 
      return; 

     if (e.NewItems != null) 
      foreach (var item in e.NewItems.Cast<T>()) 
       childSelector(item).DescendantsChanged += OnDescendantsChanged; 

     if (e.OldItems != null) 
      foreach (var item in e.OldItems.Cast<T>()) 
       childSelector(item).DescendantsChanged -= OnDescendantsChanged; 
    } 
} 

Чтобы использовать его, замените экземпляры ObservableCollection и передайте селектор в коллекцию.

public class FieldInfos 
{ 
    private ObservableBubbleCollection<Field> _fields; 

    public ObservableBubbleCollection<Field> Fields => _fields ?? (_fields = new ObservableBubbleCollection<Field>(fi => fi.Instances)); 
} 

public class Field 
{ 
    public string Name; 

    private ObservableBubbleCollection<FieldInstance> _instances; 
    public ObservableBubbleCollection<FieldInstance> Instances => _instances ?? (_instances = new ObservableBubbleCollection<FieldInstance>()); 
} 

public class FieldInstance 
{ 
    public string Id { get; set; } 
} 

static class Program 
{ 
    static void Main(string[] args) 
    { 
     var fi = new FieldInfos(); 
     fi.Fields.DescendantsChanged += (sender, e) => 
     { 
      Console.WriteLine("Change from {0}", sender.GetType()); 
     }; 

     var field = new Field(); 
     fi.Fields.Add(field); 

     field.Instances.Add(new FieldInstance()); 
     Console.ReadLine(); 
    } 
} 
+0

Асти, это потрясающе. Очень полный образец кода, который вы предоставили для иллюстрации решения. Очень ценю, что вы нашли время, чтобы обеспечить это для меня и для любого, кто придет в будущем. Пятно на! – Mike

+0

@ Майк. Добро пожаловать, Майк. Просто передав некоторые из этого рождественского духа! :) – Asti

Смежные вопросы