private void AddListener(object source, PropertyDescriptor pd, IWeakEventListener listener, EventHandler <ValueChangedEventArgs> handler) { using (WriteLock) { HybridDictionary dict = (HybridDictionary)this[source]; if (dict == null) { // no entry in the hashtable - add a new one dict = new HybridDictionary(); this[source] = dict; } ValueChangedRecord record = (ValueChangedRecord)dict[pd]; if (record == null) { // no entry in the dictionary - add a new one record = new ValueChangedRecord(this, source, pd); dict[pd] = record; } // add a listener to the list record.Add(listener, handler); // schedule a cleanup pass ScheduleCleanup(); } }
private void RemoveListener(object source, PropertyDescriptor pd, IWeakEventListener listener, EventHandler <ValueChangedEventArgs> handler) { using (WriteLock) { HybridDictionary dict = (HybridDictionary)this[source]; if (dict != null) { ValueChangedRecord record = (ValueChangedRecord)dict[pd]; if (record != null) { // remove a listener from the list record.Remove(listener, handler); // when the last listener goes away, remove the list if (record.IsEmpty) { dict.Remove(pd); } } if (dict.Count == 0) { Remove(source); } } } }
/// <summary> /// Remove a listener to the named property (empty means "any property")</summary> /// <param name="source">Source of the event</param> /// <param name="listener">The listener to remove</param> /// <param name="pd">Property descriptor for the value</param> private void PrivateRemoveListener(object source, IWeakEventListener listener, PropertyDescriptor pd) { Debug.Assert(listener != null && source != null && pd != null, "Listener, source, and pd of event cannot be null"); using (WriteLock) { HybridDictionary dict = (HybridDictionary)this[source]; if (dict != null) { ValueChangedRecord record = (ValueChangedRecord)dict[pd]; if (record != null) { // remove a listener from the list record.Remove(listener); // when the last listener goes away, remove the list if (record.IsEmpty) { dict.Remove(pd); } } if (dict.Count == 0) { Remove(source); } } } }
/// <summary> /// Add a listener to the given property</summary> /// <param name="source">Source of the event</param> /// <param name="listener">The listener to add</param> /// <param name="pd">Property descriptor for the value</param> private void PrivateAddListener(object source, IWeakEventListener listener, PropertyDescriptor pd) { Debug.Assert(listener != null && source != null && pd != null, "Listener, source, and pd of event cannot be null"); using (WriteLock) { HybridDictionary dict = (HybridDictionary)this[source]; if (dict == null) { // no entry in the hashtable - add a new one dict = new HybridDictionary(); this[source] = dict; } ValueChangedRecord record = (ValueChangedRecord)dict[pd]; if (record == null) { // no entry in the dictionary - add a new one record = new ValueChangedRecord(this, source, pd); dict[pd] = record; } // add a listener to the list record.Add(listener); // schedule a cleanup pass ScheduleCleanup(); } }
/// <summary> /// Remove dead entries from the data for the given source. Returns true if /// some entries were actually removed. /// </summary> protected override bool Purge(object source, object data, bool purgeAll) { bool foundDirt = false; HybridDictionary dict = (HybridDictionary)data; // copy the keys into a separate array, so that later on // we can change the dictionary while iterating over the keys ICollection ic = dict.Keys; PropertyDescriptor[] keys = new PropertyDescriptor[ic.Count]; ic.CopyTo(keys, 0); for (int i = keys.Length - 1; i >= 0; --i) { // for each key, remove dead entries in its list bool removeList = purgeAll || source == null; ValueChangedRecord record = (ValueChangedRecord)dict[keys[i]]; if (!removeList) { if (record.Purge()) { foundDirt = true; } removeList = record.IsEmpty; } // if there are no more entries, remove the key if (removeList) { record.StopListening(); if (!purgeAll) { dict.Remove(keys[i]); } } } // if there are no more listeners at all, remove the entry from // the main table if (dict.Count == 0) { foundDirt = true; if (source != null) // source may have been GC'd { this.Remove(source); } } return(foundDirt); }
/// <summary> /// Remove dead entries from the data for the given source. Returns true if /// some entries were actually removed. /// </summary> protected override bool Purge(object source, object data, bool purgeAll) { bool foundDirt = false; HybridDictionary dict = (HybridDictionary)data; if (!MS.Internal.BaseAppContextSwitches.EnableWeakEventMemoryImprovements) { // copy the keys into a separate array, so that later on // we can change the dictionary while iterating over the keys ICollection ic = dict.Keys; PropertyDescriptor[] keys = new PropertyDescriptor[ic.Count]; ic.CopyTo(keys, 0); for (int i = keys.Length - 1; i >= 0; --i) { // for each key, remove dead entries in its list bool removeList = purgeAll || source == null; ValueChangedRecord record = (ValueChangedRecord)dict[keys[i]]; if (!removeList) { if (record.Purge()) { foundDirt = true; } removeList = record.IsEmpty; } // if there are no more entries, remove the key if (removeList) { record.StopListening(); if (!purgeAll) { dict.Remove(keys[i]); } } } #if WeakEventTelemetry LogAllocation(ic.GetType(), 1, 12); // dict.Keys - Hashtable+KeyCollection LogAllocation(typeof(String[]), 1, 12 + ic.Count * 4); // keys #endif } else { Debug.Assert(_toRemove.Count == 0, "to-remove list should be empty"); // enumerate the dictionary using IDE explicitly rather than // foreach, to avoid allocating temporary DictionaryEntry objects IDictionaryEnumerator ide = dict.GetEnumerator() as IDictionaryEnumerator; while (ide.MoveNext()) { // for each key, remove dead entries in its list bool removeList = purgeAll || source == null; ValueChangedRecord record = (ValueChangedRecord)ide.Value; if (!removeList) { if (record.Purge()) { foundDirt = true; } removeList = record.IsEmpty; } // if there are no more entries, remove the key if (removeList) { record.StopListening(); if (!purgeAll) { _toRemove.Add((PropertyDescriptor)ide.Key); } } } // do the actual removal (outside the dictionary iteration) if (_toRemove.Count > 0) { foreach (PropertyDescriptor key in _toRemove) { dict.Remove(key); } _toRemove.Clear(); _toRemove.TrimExcess(); } #if WeakEventTelemetry Type enumeratorType = ide.GetType(); if (enumeratorType.Name.IndexOf("NodeEnumerator") >= 0) { LogAllocation(enumeratorType, 1, 24); // ListDictionary+NodeEnumerator } else { LogAllocation(enumeratorType, 1, 36); // Hashtable+HashtableEnumerator } #endif } // if there are no more listeners at all, remove the entry from // the main table if (dict.Count == 0) { foundDirt = true; if (source != null) // source may have been GC'd { this.Remove(source); } } return(foundDirt); }
private void AddListener(object source, PropertyDescriptor pd, IWeakEventListener listener, EventHandler<ValueChangedEventArgs> handler) { using (WriteLock) { HybridDictionary dict = (HybridDictionary)this[source]; if (dict == null) { // no entry in the hashtable - add a new one dict = new HybridDictionary(); this[source] = dict; } ValueChangedRecord record = (ValueChangedRecord)dict[pd]; if (record == null) { // no entry in the dictionary - add a new one record = new ValueChangedRecord(this, source, pd); dict[pd] = record; } // add a listener to the list record.Add(listener, handler); // schedule a cleanup pass ScheduleCleanup(); } }