// (c) Copyright Microsoft Corporation. // This source is subject to the Microsoft Public License (Ms-PL). // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. // All other rights reserved. using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics.CodeAnalysis; namespace System.Windows.Controls.DataVisualization.Charting { /// /// A class that rotates through a list of ResourceDictionaries. /// internal class ResourceDictionaryDispenser : IResourceDictionaryDispenser { /// /// A linked list of ResourceDictionaries dispensed. /// private LinkedList _resourceDictionariesDispensed = new LinkedList(); /// /// A bag of weak references to connected style enumerators. /// private WeakReferenceBag _resourceDictionaryEnumerators = new WeakReferenceBag(); /// /// Value indicating whether to ignore that the enumerator has /// dispensed a ResourceDictionary. /// private bool _ignoreResourceDictionaryDispensedByEnumerator; /// /// The list of ResourceDictionaries of rotate. /// private IList _resourceDictionaries; /// /// Gets or sets the list of ResourceDictionaries to rotate. /// public IList ResourceDictionaries { get { return _resourceDictionaries; } set { if (value != _resourceDictionaries) { { INotifyCollectionChanged notifyCollectionChanged = _resourceDictionaries as INotifyCollectionChanged; if (notifyCollectionChanged != null) { notifyCollectionChanged.CollectionChanged -= ResourceDictionariesCollectionChanged; } } _resourceDictionaries = value; { INotifyCollectionChanged notifyCollectionChanged = _resourceDictionaries as INotifyCollectionChanged; if (notifyCollectionChanged != null) { notifyCollectionChanged.CollectionChanged += ResourceDictionariesCollectionChanged; } } Reset(); } } } /// /// This method is raised when the ResourceDictionaries collection is changed. /// /// The source of the event. /// Information about the event. private void ResourceDictionariesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (!(e.Action == NotifyCollectionChangedAction.Add && (this.ResourceDictionaries.Count - e.NewItems.Count) == e.NewStartingIndex)) { Reset(); } } /// /// The parent of the ResourceDictionaryDispenser. /// private IResourceDictionaryDispenser _parent; /// /// Event that is invoked when the ResourceDictionaryDispenser's contents have changed. /// public event EventHandler ResourceDictionariesChanged; /// /// Gets or sets the parent of the ResourceDictionaryDispenser. /// public IResourceDictionaryDispenser Parent { get { return _parent; } set { if (_parent != value) { if (null != _parent) { _parent.ResourceDictionariesChanged -= new EventHandler(ParentResourceDictionariesChanged); } _parent = value; if (null != _parent) { _parent.ResourceDictionariesChanged += new EventHandler(ParentResourceDictionariesChanged); } OnParentChanged(); } } } /// /// Initializes a new instance of the ResourceDictionaryDispenser class. /// public ResourceDictionaryDispenser() { } /// /// Resets the state of the ResourceDictionaryDispenser and its enumerators. /// private void Reset() { OnResetting(); // Invoke event EventHandler handler = ResourceDictionariesChanged; if (null != handler) { handler.Invoke(this, EventArgs.Empty); } } /// /// Unregisters an enumerator so that it can be garbage collected. /// /// The enumerator. internal void Unregister(ResourceDictionaryEnumerator enumerator) { _resourceDictionaryEnumerators.Remove(enumerator); } /// /// Returns a rotating enumerator of ResourceDictionary objects that coordinates /// with the dispenser object to ensure that no two enumerators are on the same /// item. If the dispenser is reset or its collection is changed then the /// enumerators are also reset. /// /// A predicate that returns a value indicating /// whether to return an item. /// An enumerator of ResourceDictionaries. [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Returning a usable enumerator instance.")] public IEnumerator GetResourceDictionariesWhere(Func predicate) { ResourceDictionaryEnumerator enumerator = new ResourceDictionaryEnumerator(this, predicate); _ignoreResourceDictionaryDispensedByEnumerator = true; try { foreach (ResourceDictionaryDispensedEventArgs args in _resourceDictionariesDispensed) { enumerator.ResourceDictionaryDispenserResourceDictionaryDispensed(this, args); } } finally { _ignoreResourceDictionaryDispensedByEnumerator = false; } _resourceDictionaryEnumerators.Add(enumerator); return enumerator; } /// /// This method is raised when an enumerator dispenses a ResourceDictionary. /// /// The source of the event. /// Information about the event. internal void EnumeratorResourceDictionaryDispensed(object sender, ResourceDictionaryDispensedEventArgs e) { if (!_ignoreResourceDictionaryDispensedByEnumerator) { OnEnumeratorResourceDictionaryDispensed(this, e); } } /// /// Raises the ParentChanged event. /// private void OnParentChanged() { foreach (ResourceDictionaryEnumerator enumerator in _resourceDictionaryEnumerators) { enumerator.ResourceDictionaryDispenserParentChanged(); } } /// /// Raises the EnumeratorResourceDictionaryDispensed event. /// /// The source of the event. /// Information about the event. private void OnEnumeratorResourceDictionaryDispensed(object source, ResourceDictionaryDispensedEventArgs args) { // Remove this item from the list of dispensed styles. _resourceDictionariesDispensed.Remove(args); // Add this item to the end of the list of dispensed styles. _resourceDictionariesDispensed.AddLast(args); foreach (ResourceDictionaryEnumerator enumerator in _resourceDictionaryEnumerators) { enumerator.ResourceDictionaryDispenserResourceDictionaryDispensed(source, args); } } /// /// This method raises the EnumeratorsResetting event. /// private void OnResetting() { _resourceDictionariesDispensed.Clear(); foreach (ResourceDictionaryEnumerator enumerator in _resourceDictionaryEnumerators) { enumerator.ResourceDictionaryDispenserResetting(); } } /// /// Handles the Parent's ResourceDictionariesChanged event. /// /// Parent instance. /// Event args. private void ParentResourceDictionariesChanged(object sender, EventArgs e) { Reset(); } } }