using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; using System.Runtime.Serialization; using System.Threading; namespace Umbraco.Core.Models { /// /// Represents a collection of objects /// [Serializable] [DataContract] public class PropertyGroupCollection : KeyedCollection, INotifyCollectionChanged { private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim(); internal Action OnAdd; internal PropertyGroupCollection() { } public PropertyGroupCollection(IEnumerable groups) { Reset(groups); } /// /// Resets the collection to only contain the instances referenced in the parameter. /// /// The property groups. /// internal void Reset(IEnumerable groups) { Clear(); groups.ForEach(Add); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } protected override void SetItem(int index, PropertyGroup item) { base.SetItem(index, item); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); } protected override void RemoveItem(int index) { var removed = this[index]; base.RemoveItem(index); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed)); } protected override void InsertItem(int index, PropertyGroup item) { base.InsertItem(index, item); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); } protected override void ClearItems() { base.ClearItems(); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } internal new void Add(PropertyGroup item) { using (new WriteLock(_addLocker)) { var key = GetKeyForItem(item); if (key != null) { var exists = this.Contains(key); if (exists) { SetItem(IndexOfKey(key), item); return; } } base.Add(item); OnAdd.IfNotNull(x => x.Invoke());//Could this not be replaced by a Mandate/Contract for ensuring item is not null OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); } } /// /// Determines whether this collection contains a whose name matches the specified parameter. /// /// Name of the PropertyGroup. /// true if the collection contains the specified name; otherwise, false. /// public new bool Contains(string groupName) { return this.Any(x => x.Name == groupName); } public void RemoveItem(string propertyGroupName) { var key = IndexOfKey(propertyGroupName); //Only removes an item if the key was found if (key != -1) RemoveItem(key); } public int IndexOfKey(string key) { for (var i = 0; i < this.Count; i++) { if (this[i].Name == key) { return i; } } return -1; } protected override string GetKeyForItem(PropertyGroup item) { return item.Name; } public event NotifyCollectionChangedEventHandler CollectionChanged; protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs args) { if (CollectionChanged != null) { CollectionChanged(this, args); } } } }