// Copyright (C) Stichting Deltares 2016. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program. If not, see . // // All names, logos, and references to "Deltares" are registered trademarks of // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. using System; using System.Collections.Generic; namespace Core.Common.Base { /// /// Class that implements in a way that a hierarchy of objects can be observed. /// /// /// The root container () being observed by instances of this class can be dynamically changed. /// /// The type of the item containers that specify the object hierarchy. /// The type of items (in the containers) that should be observed. public class RecursiveObserver : IObserver, IDisposable where TContainer : class, IObservable where TObservable : class, IObservable { private TContainer rootContainer; private readonly Action updateObserverAction; private readonly Func> getChildren; private readonly IList observedContainers = new List(); private readonly IList observedChildren = new List(); private readonly Observer containerObserver; /// /// Creates a new instance of the class. /// /// The action to perform on notifications coming from one of the items of the hierarchy. /// The method used for recursively obtaining the children of objects in the hierarchy. public RecursiveObserver(Action updateObserverAction, Func> getChildren) { this.updateObserverAction = updateObserverAction; this.getChildren = getChildren; // Ensure subscriptions are updated (detach/attach) on changes in the hierarchy containerObserver = new Observer(UpdateObservedObjects); } /// /// Gets or sets the root container. /// public TContainer Observable { get { return rootContainer; } set { rootContainer = value; UpdateObservedObjects(); } } public void Dispose() { Observable = null; } public void UpdateObserver() { updateObserverAction(); } private void UpdateObservedObjects() { // Detach from the currently observed containers foreach (var observedObject in observedContainers) { observedObject.Detach(containerObserver); } // Detach from the currently observed children foreach (var observedObject in observedChildren) { observedObject.Detach(this); } // Clear the lists of observed objects observedContainers.Clear(); observedChildren.Clear(); // If relevant, start observing objects again if (rootContainer != null) { ObserveObjectsRecursively(rootContainer); } } private void ObserveObjectsRecursively(TContainer container) { container.Attach(containerObserver); observedContainers.Add(container); var observable = container as TObservable; if (observable != null) { observable.Attach(this); observedChildren.Add(observable); } foreach (var child in getChildren(container)) { if (child is TContainer) { ObserveObjectsRecursively((TContainer) child); } else if (child is TObservable) { observable = (TObservable) child; observable.Attach(this); observedChildren.Add(observable); } } } } }