diff --git a/src/Main/Base/Project/Dom/IModelCollection.cs b/src/Main/Base/Project/Dom/IModelCollection.cs index 85a8f6b60a..608c686572 100644 --- a/src/Main/Base/Project/Dom/IModelCollection.cs +++ b/src/Main/Base/Project/Dom/IModelCollection.cs @@ -15,6 +15,49 @@ namespace ICSharpCode.SharpDevelop.Dom /// public delegate void ModelCollectionChangedEventHandler(IReadOnlyCollection removedItems, IReadOnlyCollection addedItems); + public class ModelCollectionChangedEvent + { + List> _handlers = new List>(); + +// public static ModelCollectionChangedEvent operator+(ModelCollectionChangedEvent eventObject, ModelCollectionChangedEventHandler handler) +// { +// eventObject._handlers.Add(handler); +// return eventObject; +// } + + public void AddHandler(ModelCollectionChangedEventHandler handler) + { + _handlers.Add(handler); + } + +// public static ModelCollectionChangedEvent operator-(ModelCollectionChangedEvent eventObject, ModelCollectionChangedEventHandler handler) +// { +// eventObject._handlers.Remove(handler); +// return eventObject; +// } + + public void RemoveHandler(ModelCollectionChangedEventHandler handler) + { + _handlers.Remove(handler); + } + + public void Fire(IReadOnlyCollection removedItems, IReadOnlyCollection addedItems) + { + foreach (var handler in _handlers) { + if (handler != null) { + handler(removedItems, addedItems); + } + } + } + + public bool ContainsHandlers + { + get { + return _handlers.Count > 0; + } + } + } + /// /// A read-only collection that provides change notifications. /// diff --git a/src/Main/Base/Project/Dom/ModelCollectionLinq.cs b/src/Main/Base/Project/Dom/ModelCollectionLinq.cs index fe5a9bf3e5..2c3e911c26 100644 --- a/src/Main/Base/Project/Dom/ModelCollectionLinq.cs +++ b/src/Main/Base/Project/Dom/ModelCollectionLinq.cs @@ -70,6 +70,7 @@ namespace ICSharpCode.SharpDevelop.Dom sealed class SelectManyModelCollection : IModelCollection { + readonly ModelCollectionChangedEvent collectionChangedEvent; readonly IModelCollection source; readonly Func> collectionSelector; readonly Func resultSelector; @@ -80,10 +81,9 @@ namespace ICSharpCode.SharpDevelop.Dom this.source = source; this.collectionSelector = collectionSelector; this.resultSelector = resultSelector; + collectionChangedEvent = new ModelCollectionChangedEvent(); } - ModelCollectionChangedEventHandler collectionChanged; - public event ModelCollectionChangedEventHandler CollectionChanged { add { if (value == null) @@ -97,13 +97,13 @@ namespace ICSharpCode.SharpDevelop.Dom inputCollections.Add(inputCollection); } } - collectionChanged += value; + collectionChangedEvent.AddHandler(value); } remove { - if (collectionChanged == null) + if (!collectionChangedEvent.ContainsHandlers) return; - collectionChanged -= value; - if (collectionChanged == null) { + collectionChangedEvent.RemoveHandler(value); + if (!collectionChangedEvent.ContainsHandlers) { source.CollectionChanged -= OnSourceCollectionChanged; foreach (var inputCollection in inputCollections) { inputCollection.UnregisterEvent(); @@ -115,8 +115,7 @@ namespace ICSharpCode.SharpDevelop.Dom void OnCollectionChanged(IReadOnlyCollection removedItems, IReadOnlyCollection addedItems) { - if (collectionChanged != null) - collectionChanged(removedItems, addedItems); + collectionChangedEvent.Fire(removedItems, addedItems); } void OnSourceCollectionChanged(IReadOnlyCollection removedItems, IReadOnlyCollection addedItems) diff --git a/src/Main/Base/Project/Dom/SimpleModelCollection.cs b/src/Main/Base/Project/Dom/SimpleModelCollection.cs index eb5eb16560..b91b83193c 100644 --- a/src/Main/Base/Project/Dom/SimpleModelCollection.cs +++ b/src/Main/Base/Project/Dom/SimpleModelCollection.cs @@ -16,6 +16,7 @@ namespace ICSharpCode.SharpDevelop.Dom /// public class SimpleModelCollection : IMutableModelCollection { + readonly ModelCollectionChangedEvent collectionChangedEvent; readonly List list; List addedItems; List removedItems; @@ -23,11 +24,13 @@ namespace ICSharpCode.SharpDevelop.Dom public SimpleModelCollection() { this.list = new List(); + collectionChangedEvent = new ModelCollectionChangedEvent(); } public SimpleModelCollection(IEnumerable items) { this.list = new List(items); + collectionChangedEvent = new ModelCollectionChangedEvent(); } protected void CheckReentrancy() @@ -41,7 +44,15 @@ namespace ICSharpCode.SharpDevelop.Dom } #region CollectionChanged / BatchUpdate() - public event ModelCollectionChangedEventHandler CollectionChanged; + public event ModelCollectionChangedEventHandler CollectionChanged + { + add { + collectionChangedEvent.AddHandler(value); + } + remove { + collectionChangedEvent.RemoveHandler(value); + } + } bool isWithinBatchOperation; bool isRaisingEvent; @@ -64,9 +75,7 @@ namespace ICSharpCode.SharpDevelop.Dom protected virtual void OnCollectionChanged(IReadOnlyCollection removedItems, IReadOnlyCollection addedItems) { - var handler = CollectionChanged; - if (handler != null) - handler(removedItems, addedItems); + collectionChangedEvent.Fire(removedItems, addedItems); } public virtual IDisposable BatchUpdate() diff --git a/src/Main/Base/Project/Src/Project/MSBuildConfigurationOrPlatformNameCollection.cs b/src/Main/Base/Project/Src/Project/MSBuildConfigurationOrPlatformNameCollection.cs index 207114df0c..8bf097a07a 100644 --- a/src/Main/Base/Project/Src/Project/MSBuildConfigurationOrPlatformNameCollection.cs +++ b/src/Main/Base/Project/Src/Project/MSBuildConfigurationOrPlatformNameCollection.cs @@ -16,9 +16,8 @@ namespace ICSharpCode.SharpDevelop.Project /// class MSBuildConfigurationOrPlatformNameCollection : IConfigurationOrPlatformNameCollection { - public event ModelCollectionChangedEventHandler CollectionChanged; - volatile IReadOnlyList listSnapshot = EmptyList.Instance; + readonly ModelCollectionChangedEvent collectionChangedEvent; readonly MSBuildBasedProject project; readonly bool isPlatform; @@ -26,6 +25,7 @@ namespace ICSharpCode.SharpDevelop.Project { this.project = project; this.isPlatform = isPlatform; + collectionChangedEvent = new ModelCollectionChangedEvent(); } internal void SetContents(IEnumerable updatedItems) @@ -33,13 +33,21 @@ namespace ICSharpCode.SharpDevelop.Project this.listSnapshot = updatedItems.ToArray(); } + public event ModelCollectionChangedEventHandler CollectionChanged + { + add { + collectionChangedEvent.AddHandler(value); + } + remove { + collectionChangedEvent.RemoveHandler(value); + } + } + internal void OnCollectionChanged(IReadOnlyCollection oldItems, IReadOnlyCollection newItems) { if (oldItems.SequenceEqual(newItems)) return; - var eh = CollectionChanged; - if (eh != null) - eh(oldItems, newItems); + collectionChangedEvent.Fire(oldItems, newItems); } #region IReadOnlyCollection implementation diff --git a/src/Main/SharpDevelop/Dom/NestedTypeDefinitionModelCollection.cs b/src/Main/SharpDevelop/Dom/NestedTypeDefinitionModelCollection.cs index 2797980852..92e1b70369 100644 --- a/src/Main/SharpDevelop/Dom/NestedTypeDefinitionModelCollection.cs +++ b/src/Main/SharpDevelop/Dom/NestedTypeDefinitionModelCollection.cs @@ -11,15 +11,25 @@ namespace ICSharpCode.SharpDevelop.Dom { sealed class NestedTypeDefinitionModelCollection : IModelCollection { + readonly ModelCollectionChangedEvent collectionChangedEvent; readonly IEntityModelContext context; List list = new List(); public NestedTypeDefinitionModelCollection(IEntityModelContext context) { this.context = context; + collectionChangedEvent = new ModelCollectionChangedEvent(); } - public event ModelCollectionChangedEventHandler CollectionChanged; + public event ModelCollectionChangedEventHandler CollectionChanged + { + add { + collectionChangedEvent.AddHandler(value); + } + remove { + collectionChangedEvent.RemoveHandler(value); + } + } public IReadOnlyCollection CreateSnapshot() { @@ -107,9 +117,9 @@ namespace ICSharpCode.SharpDevelop.Dom } } // Raise the event if necessary: - if (CollectionChanged != null && (oldModels != null || newModels != null)) { + if (collectionChangedEvent.ContainsHandlers && (oldModels != null || newModels != null)) { IReadOnlyCollection emptyList = EmptyList.Instance; - CollectionChanged(oldModels ?? emptyList, newModels ?? emptyList); + collectionChangedEvent.Fire(oldModels ?? emptyList, newModels ?? emptyList); } } } diff --git a/src/Main/SharpDevelop/Dom/TopLevelTypeDefinitionModelCollection.cs b/src/Main/SharpDevelop/Dom/TopLevelTypeDefinitionModelCollection.cs index 137f04002d..5b65d65f82 100644 --- a/src/Main/SharpDevelop/Dom/TopLevelTypeDefinitionModelCollection.cs +++ b/src/Main/SharpDevelop/Dom/TopLevelTypeDefinitionModelCollection.cs @@ -16,6 +16,7 @@ namespace ICSharpCode.SharpDevelop.Dom /// sealed class TopLevelTypeDefinitionModelCollection : ITypeDefinitionModelCollection { + readonly ModelCollectionChangedEvent collectionChangedEvent; readonly IEntityModelContext context; Dictionary dict = new Dictionary(); @@ -24,9 +25,18 @@ namespace ICSharpCode.SharpDevelop.Dom if (context == null) throw new ArgumentNullException("context"); this.context = context; + collectionChangedEvent = new ModelCollectionChangedEvent(); } - public event ModelCollectionChangedEventHandler CollectionChanged; + public event ModelCollectionChangedEventHandler CollectionChanged + { + add { + collectionChangedEvent.AddHandler(value); + } + remove { + collectionChangedEvent.RemoveHandler(value); + } + } public IReadOnlyCollection CreateSnapshot() { @@ -122,9 +132,9 @@ namespace ICSharpCode.SharpDevelop.Dom } } // Raise the event if necessary: - if (CollectionChanged != null && (oldModels != null || newModels != null)) { + if (collectionChangedEvent.ContainsHandlers && (oldModels != null || newModels != null)) { IReadOnlyCollection emptyList = EmptyList.Instance; - CollectionChanged(oldModels ?? emptyList, newModels ?? emptyList); + collectionChangedEvent.Fire(oldModels ?? emptyList, newModels ?? emptyList); } } diff --git a/src/Main/SharpDevelop/Dom/TypeDefinitionModel.cs b/src/Main/SharpDevelop/Dom/TypeDefinitionModel.cs index c729f72de3..97eea35738 100644 --- a/src/Main/SharpDevelop/Dom/TypeDefinitionModel.cs +++ b/src/Main/SharpDevelop/Dom/TypeDefinitionModel.cs @@ -105,12 +105,14 @@ namespace ICSharpCode.SharpDevelop.Dom #region Members collection sealed class MemberCollection : IModelCollection { + readonly ModelCollectionChangedEvent collectionChangedEvent; readonly TypeDefinitionModel parent; List> lists = new List>(); public MemberCollection(TypeDefinitionModel parent) { this.parent = parent; + collectionChangedEvent = new ModelCollectionChangedEvent(); } public void InsertPart(int partIndex, IUnresolvedTypeDefinition newPart) @@ -120,16 +122,14 @@ namespace ICSharpCode.SharpDevelop.Dom newItems.Add(new MemberModel(parent.context, newMember) { strongParentCollectionReference = this }); } lists.Insert(partIndex, newItems); - if (collectionChanged != null) - collectionChanged(EmptyList.Instance, newItems); + collectionChangedEvent.Fire(EmptyList.Instance, newItems); } public void RemovePart(int partIndex) { var oldItems = lists[partIndex]; lists.RemoveAt(partIndex); - if (collectionChanged != null) - collectionChanged(oldItems, EmptyList.Instance); + collectionChangedEvent.Fire(oldItems, EmptyList.Instance); } public void UpdatePart(int partIndex, IUnresolvedTypeDefinition newPart) @@ -158,7 +158,7 @@ namespace ICSharpCode.SharpDevelop.Dom // We might try to be clever here and find a LCS so that we only update the members that were actually changed, // or we might consider moving members around (INotifyCollectionChanged supports moves) // However, the easiest solution by far is to just remove + readd the whole middle portion. - var oldItems = collectionChanged != null ? list.GetRange(startPos, endPosOld - startPos) : null; + var oldItems = collectionChangedEvent.ContainsHandlers ? list.GetRange(startPos, endPosOld - startPos) : null; list.RemoveRange(startPos, endPosOld - startPos); var newItems = new MemberModel[endPosNew - startPos]; for (int i = 0; i < newItems.Length; i++) { @@ -166,8 +166,8 @@ namespace ICSharpCode.SharpDevelop.Dom newItems[i].strongParentCollectionReference = this; } list.InsertRange(startPos, newItems); - if (collectionChanged != null && (oldItems.Count > 0 || newItems.Length > 0)) { - collectionChanged(oldItems, newItems); + if (collectionChangedEvent.ContainsHandlers && (oldItems.Count > 0 || newItems.Length > 0)) { + collectionChangedEvent.Fire(oldItems, newItems); } } @@ -176,18 +176,16 @@ namespace ICSharpCode.SharpDevelop.Dom return memberModel.SymbolKind == newMember.SymbolKind && memberModel.Name == newMember.Name; } - ModelCollectionChangedEventHandler collectionChanged; - public event ModelCollectionChangedEventHandler CollectionChanged { add { - collectionChanged += value; + collectionChangedEvent.AddHandler(value); // Set strong reference to collection while there are event listeners - if (collectionChanged != null) + if (collectionChangedEvent.ContainsHandlers) parent.membersStrongReference = this; } remove { - collectionChanged -= value; - if (collectionChanged == null) + collectionChangedEvent.RemoveHandler(value); + if (!collectionChangedEvent.ContainsHandlers) parent.membersStrongReference = null; } } diff --git a/src/Main/SharpDevelop/Project/Configuration/SolutionConfigurationOrPlatformNameCollection.cs b/src/Main/SharpDevelop/Project/Configuration/SolutionConfigurationOrPlatformNameCollection.cs index 6044b789ac..f25220b88e 100644 --- a/src/Main/SharpDevelop/Project/Configuration/SolutionConfigurationOrPlatformNameCollection.cs +++ b/src/Main/SharpDevelop/Project/Configuration/SolutionConfigurationOrPlatformNameCollection.cs @@ -22,8 +22,7 @@ namespace ICSharpCode.SharpDevelop.Project /// class SolutionConfigurationOrPlatformNameCollection : IConfigurationOrPlatformNameCollection { - public event ModelCollectionChangedEventHandler CollectionChanged; - + readonly ModelCollectionChangedEvent collectionChangedEvent; readonly List list = new List(); volatile IReadOnlyList listSnapshot = EmptyList.Instance; readonly ISolution solution; @@ -33,14 +32,23 @@ namespace ICSharpCode.SharpDevelop.Project { this.solution = solution; this.isPlatform = isPlatform; + collectionChangedEvent = new ModelCollectionChangedEvent(); } void OnCollectionChanged(IReadOnlyCollection oldItems, IReadOnlyCollection newItems) { this.listSnapshot = list.ToArray(); - var eh = CollectionChanged; - if (eh != null) - eh(oldItems, newItems); + collectionChangedEvent.Fire(oldItems, newItems); + } + + public event ModelCollectionChangedEventHandler CollectionChanged + { + add { + collectionChangedEvent.AddHandler(value); + } + remove { + collectionChangedEvent.RemoveHandler(value); + } } #region IReadOnlyCollection implementation