PropertyChangedEventManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / System / ComponentModel / PropertyChangedEventManager.cs / 1305600 / PropertyChangedEventManager.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: Manager for the PropertyChanged event in the "weak event listener" 
//              pattern.  See WeakEventTable.cs for an overview. 
//
//--------------------------------------------------------------------------- 

using System;
using System.Collections;       // ICollection
using System.Collections.Specialized;   // HybridDictionary 
using System.ComponentModel;    // INotifyPropertyChanged
using System.Diagnostics;       // Debug 
using System.Windows;           // WeakEventManager 

namespace System.ComponentModel 
{
    /// 
    /// Manager for the INotifyPropertyChanged.PropertyChanged event.
    ///  
    public class PropertyChangedEventManager : WeakEventManager
    { 
        #region Constructors 

        // 
        //  Constructors
        //

        private PropertyChangedEventManager() 
        {
        } 
 
        #endregion Constructors
 
        #region Public Methods

        //
        //  Public Methods 
        //
 
        ///  
        /// Add a listener to the given source's event.
        ///  
        public static void AddListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName)
        {
            if (source == null)
                throw new ArgumentNullException("source"); 
            if (listener == null)
                throw new ArgumentNullException("listener"); 
 
            CurrentManager.PrivateAddListener(source, listener, propertyName);
        } 

        /// 
        /// Remove a listener to the given source's event.
        ///  
        public static void RemoveListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName)
        { 
            /* for app-compat, allow RemoveListener(null, x) - it's a no-op (see Dev10 796788) 
            if (source == null)
                throw new ArgumentNullException("source"); 
            */
            if (listener == null)
                throw new ArgumentNullException("listener");
 
            CurrentManager.PrivateRemoveListener(source, listener, propertyName);
        } 
 
        #endregion Public Methods
 
        #region Protected Methods

        //
        //  Protected Methods 
        //
 
        ///  
        /// Listen to the given source for the event.
        ///  
        protected override void StartListening(object source)
        {
            INotifyPropertyChanged typedSource = (INotifyPropertyChanged)source;
            typedSource.PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged); 
        }
 
        ///  
        /// Stop listening to the given source for the event.
        ///  
        protected override void StopListening(object source)
        {
            INotifyPropertyChanged typedSource = (INotifyPropertyChanged)source;
            typedSource.PropertyChanged -= new PropertyChangedEventHandler(OnPropertyChanged); 
        }
 
        ///  
        /// Remove dead entries from the data for the given source.   Returns true if
        /// some entries were actually removed. 
        /// 
        protected override bool Purge(object source, object data, bool purgeAll)
        {
            bool foundDirt = false; 

            if (!purgeAll) 
            { 
                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;
                String[] keys = new String[ic.Count]; 
                ic.CopyTo(keys, 0);
 
                for (int i=keys.Length-1; i>=0; --i) 
                {
                    if (keys[i] == AllListenersKey) 
                        continue;       // ignore the special entry for now

                    // for each key, remove dead entries in its list
                    bool removeList = purgeAll || source == null; 

                    if (!removeList) 
                    { 
                        ListenerList list = (ListenerList)dict[keys[i]];
 
                        if (ListenerList.PrepareForWriting(ref list))
                            dict[keys[i]] = list;

                        if (list.Purge()) 
                            foundDirt = true;
 
                        removeList = (list.IsEmpty); 
                    }
 
                    // if there are no more entries, remove the key
                    if (removeList)
                    {
                        dict.Remove(keys[i]); 
                    }
                } 
 
                if (dict.Count == 0)
                { 
                    // if there are no more listeners at all, remove the entry from
                    // the main table, and prepare to stop listening
                    purgeAll = true;
                    if (source != null)     // source may have been GC'd 
                    {
                        this.Remove(source); 
                    } 
                }
                else if (foundDirt) 
                {
                    // if any entries were purged, invalidate the special entry
                    dict.Remove(AllListenersKey);
                    _proposedAllListenersList = null; 
                }
            } 
 
            if (purgeAll)
            { 
                // stop listening.  List cleanup is handled by Purge()
                if (source != null) // source may have been GC'd
                {
                    StopListening(source); 
                }
                foundDirt = true; 
            } 

            return foundDirt; 
        }

        #endregion Protected Methods
 
        #region Private Properties
 
        // 
        //  Private Properties
        // 

        // get the event manager for the current thread
        private static PropertyChangedEventManager CurrentManager
        { 
            get
            { 
                Type managerType = typeof(PropertyChangedEventManager); 
                PropertyChangedEventManager manager = (PropertyChangedEventManager)GetCurrentManager(managerType);
 
                // at first use, create and register a new manager
                if (manager == null)
                {
                    manager = new PropertyChangedEventManager(); 
                    SetCurrentManager(managerType, manager);
                } 
 
                return manager;
            } 
        }

        #endregion Private Properties
 
        #region Private Methods
 
        // 
        //  Private Methods
        // 

        // PropertyChanged is a special case - we superimpose per-property granularity
        // on top of this event, by keeping separate lists of listeners for
        // each property. 

        // Add a listener to the named property (empty means "any property") 
        private void PrivateAddListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName) 
        {
            Debug.Assert(listener != null && source != null && propertyName != null, 
                "Listener, source, and propertyName 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(true /* case insensitive */);

                    this[source] = dict;
 
                    // listen for the desired events
                    StartListening(source); 
                } 

                ListenerList list = (ListenerList)dict[propertyName]; 

                if (list == null)
                {
                    // no entry in the dictionary - add a new one 
                    list = new ListenerList();
 
                    dict[propertyName] = list; 
                }
 
                // make sure list is ready for writing
                if (ListenerList.PrepareForWriting(ref list))
                {
                    dict[propertyName] = list; 
                }
 
                // add a listener to the list 
                list.Add(listener);
                dict.Remove(AllListenersKey);   // invalidate list of all listeners 
                _proposedAllListenersList = null;

                // schedule a cleanup pass
                ScheduleCleanup(); 
            }
        } 
 
        // Remove a listener to the named property (empty means "any property")
        private void PrivateRemoveListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName) 
        {
            Debug.Assert(listener != null && source != null && propertyName != null,
                "Listener, source, and propertyName of event cannot be null");
 
            using (WriteLock)
            { 
                HybridDictionary dict = (HybridDictionary)this[source]; 

                if (dict != null) 
                {
                    ListenerList list = (ListenerList)dict[propertyName];

                    if (list != null) 
                    {
                        // make sure list is ready for writing 
                        if (ListenerList.PrepareForWriting(ref list)) 
                        {
                            dict[propertyName] = list; 
                        }

                        // remove a listener from the list
                        list.Remove(listener); 

                        // when the last listener goes away, remove the list 
                        if (list.IsEmpty) 
                        {
                            dict.Remove(propertyName); 
                        }
                    }

                    if (dict.Count == 0) 
                    {
                        StopListening(source); 
 
                        Remove(source);
                    } 

                    dict.Remove(AllListenersKey);   // invalidate list of all listeners
                    _proposedAllListenersList = null;
                } 
            }
        } 
 
        // event handler for PropertyChanged event
        private void OnPropertyChanged(object sender, PropertyChangedEventArgs args) 
        {
            ListenerList list;
            string propertyName = args.PropertyName;
 
            // get the list of listeners
            using (ReadLock) 
            { 
                // look up the list of listeners
                HybridDictionary dict = (HybridDictionary)this[sender]; 

                if (dict == null)
                {
                    // this can happen when the last listener stops listening, but the 
                    // source raises the event on another thread after the dictionary
                    // has been removed (bug 1235351) 
                    list = ListenerList.Empty; 
                }
                else if (!String.IsNullOrEmpty(propertyName)) 
                {
                    // source has changed a particular property.  Notify targets
                    // who are listening either for this property or for all properties.
                    ListenerList listeners = (ListenerList)dict[propertyName]; 
                    ListenerList genericListeners = (ListenerList)dict[String.Empty];
 
                    if (genericListeners == null) 
                    {
                        if (listeners != null) 
                        {
                            list = listeners;           // only specific listeners
                        }
                        else 
                        {
                            list = ListenerList.Empty;  // no listeners at all 
                        } 
                    }
                    else 
                    {
                        if (listeners != null)
                        {
                            // there are both specific and generic listeners - 
                            // combine the two lists.
                            list = new ListenerList(listeners.Count + genericListeners.Count); 
                            for (int i=0, n=listeners.Count; i
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: Manager for the PropertyChanged event in the "weak event listener" 
//              pattern.  See WeakEventTable.cs for an overview. 
//
//--------------------------------------------------------------------------- 

using System;
using System.Collections;       // ICollection
using System.Collections.Specialized;   // HybridDictionary 
using System.ComponentModel;    // INotifyPropertyChanged
using System.Diagnostics;       // Debug 
using System.Windows;           // WeakEventManager 

namespace System.ComponentModel 
{
    /// 
    /// Manager for the INotifyPropertyChanged.PropertyChanged event.
    ///  
    public class PropertyChangedEventManager : WeakEventManager
    { 
        #region Constructors 

        // 
        //  Constructors
        //

        private PropertyChangedEventManager() 
        {
        } 
 
        #endregion Constructors
 
        #region Public Methods

        //
        //  Public Methods 
        //
 
        ///  
        /// Add a listener to the given source's event.
        ///  
        public static void AddListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName)
        {
            if (source == null)
                throw new ArgumentNullException("source"); 
            if (listener == null)
                throw new ArgumentNullException("listener"); 
 
            CurrentManager.PrivateAddListener(source, listener, propertyName);
        } 

        /// 
        /// Remove a listener to the given source's event.
        ///  
        public static void RemoveListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName)
        { 
            /* for app-compat, allow RemoveListener(null, x) - it's a no-op (see Dev10 796788) 
            if (source == null)
                throw new ArgumentNullException("source"); 
            */
            if (listener == null)
                throw new ArgumentNullException("listener");
 
            CurrentManager.PrivateRemoveListener(source, listener, propertyName);
        } 
 
        #endregion Public Methods
 
        #region Protected Methods

        //
        //  Protected Methods 
        //
 
        ///  
        /// Listen to the given source for the event.
        ///  
        protected override void StartListening(object source)
        {
            INotifyPropertyChanged typedSource = (INotifyPropertyChanged)source;
            typedSource.PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged); 
        }
 
        ///  
        /// Stop listening to the given source for the event.
        ///  
        protected override void StopListening(object source)
        {
            INotifyPropertyChanged typedSource = (INotifyPropertyChanged)source;
            typedSource.PropertyChanged -= new PropertyChangedEventHandler(OnPropertyChanged); 
        }
 
        ///  
        /// Remove dead entries from the data for the given source.   Returns true if
        /// some entries were actually removed. 
        /// 
        protected override bool Purge(object source, object data, bool purgeAll)
        {
            bool foundDirt = false; 

            if (!purgeAll) 
            { 
                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;
                String[] keys = new String[ic.Count]; 
                ic.CopyTo(keys, 0);
 
                for (int i=keys.Length-1; i>=0; --i) 
                {
                    if (keys[i] == AllListenersKey) 
                        continue;       // ignore the special entry for now

                    // for each key, remove dead entries in its list
                    bool removeList = purgeAll || source == null; 

                    if (!removeList) 
                    { 
                        ListenerList list = (ListenerList)dict[keys[i]];
 
                        if (ListenerList.PrepareForWriting(ref list))
                            dict[keys[i]] = list;

                        if (list.Purge()) 
                            foundDirt = true;
 
                        removeList = (list.IsEmpty); 
                    }
 
                    // if there are no more entries, remove the key
                    if (removeList)
                    {
                        dict.Remove(keys[i]); 
                    }
                } 
 
                if (dict.Count == 0)
                { 
                    // if there are no more listeners at all, remove the entry from
                    // the main table, and prepare to stop listening
                    purgeAll = true;
                    if (source != null)     // source may have been GC'd 
                    {
                        this.Remove(source); 
                    } 
                }
                else if (foundDirt) 
                {
                    // if any entries were purged, invalidate the special entry
                    dict.Remove(AllListenersKey);
                    _proposedAllListenersList = null; 
                }
            } 
 
            if (purgeAll)
            { 
                // stop listening.  List cleanup is handled by Purge()
                if (source != null) // source may have been GC'd
                {
                    StopListening(source); 
                }
                foundDirt = true; 
            } 

            return foundDirt; 
        }

        #endregion Protected Methods
 
        #region Private Properties
 
        // 
        //  Private Properties
        // 

        // get the event manager for the current thread
        private static PropertyChangedEventManager CurrentManager
        { 
            get
            { 
                Type managerType = typeof(PropertyChangedEventManager); 
                PropertyChangedEventManager manager = (PropertyChangedEventManager)GetCurrentManager(managerType);
 
                // at first use, create and register a new manager
                if (manager == null)
                {
                    manager = new PropertyChangedEventManager(); 
                    SetCurrentManager(managerType, manager);
                } 
 
                return manager;
            } 
        }

        #endregion Private Properties
 
        #region Private Methods
 
        // 
        //  Private Methods
        // 

        // PropertyChanged is a special case - we superimpose per-property granularity
        // on top of this event, by keeping separate lists of listeners for
        // each property. 

        // Add a listener to the named property (empty means "any property") 
        private void PrivateAddListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName) 
        {
            Debug.Assert(listener != null && source != null && propertyName != null, 
                "Listener, source, and propertyName 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(true /* case insensitive */);

                    this[source] = dict;
 
                    // listen for the desired events
                    StartListening(source); 
                } 

                ListenerList list = (ListenerList)dict[propertyName]; 

                if (list == null)
                {
                    // no entry in the dictionary - add a new one 
                    list = new ListenerList();
 
                    dict[propertyName] = list; 
                }
 
                // make sure list is ready for writing
                if (ListenerList.PrepareForWriting(ref list))
                {
                    dict[propertyName] = list; 
                }
 
                // add a listener to the list 
                list.Add(listener);
                dict.Remove(AllListenersKey);   // invalidate list of all listeners 
                _proposedAllListenersList = null;

                // schedule a cleanup pass
                ScheduleCleanup(); 
            }
        } 
 
        // Remove a listener to the named property (empty means "any property")
        private void PrivateRemoveListener(INotifyPropertyChanged source, IWeakEventListener listener, string propertyName) 
        {
            Debug.Assert(listener != null && source != null && propertyName != null,
                "Listener, source, and propertyName of event cannot be null");
 
            using (WriteLock)
            { 
                HybridDictionary dict = (HybridDictionary)this[source]; 

                if (dict != null) 
                {
                    ListenerList list = (ListenerList)dict[propertyName];

                    if (list != null) 
                    {
                        // make sure list is ready for writing 
                        if (ListenerList.PrepareForWriting(ref list)) 
                        {
                            dict[propertyName] = list; 
                        }

                        // remove a listener from the list
                        list.Remove(listener); 

                        // when the last listener goes away, remove the list 
                        if (list.IsEmpty) 
                        {
                            dict.Remove(propertyName); 
                        }
                    }

                    if (dict.Count == 0) 
                    {
                        StopListening(source); 
 
                        Remove(source);
                    } 

                    dict.Remove(AllListenersKey);   // invalidate list of all listeners
                    _proposedAllListenersList = null;
                } 
            }
        } 
 
        // event handler for PropertyChanged event
        private void OnPropertyChanged(object sender, PropertyChangedEventArgs args) 
        {
            ListenerList list;
            string propertyName = args.PropertyName;
 
            // get the list of listeners
            using (ReadLock) 
            { 
                // look up the list of listeners
                HybridDictionary dict = (HybridDictionary)this[sender]; 

                if (dict == null)
                {
                    // this can happen when the last listener stops listening, but the 
                    // source raises the event on another thread after the dictionary
                    // has been removed (bug 1235351) 
                    list = ListenerList.Empty; 
                }
                else if (!String.IsNullOrEmpty(propertyName)) 
                {
                    // source has changed a particular property.  Notify targets
                    // who are listening either for this property or for all properties.
                    ListenerList listeners = (ListenerList)dict[propertyName]; 
                    ListenerList genericListeners = (ListenerList)dict[String.Empty];
 
                    if (genericListeners == null) 
                    {
                        if (listeners != null) 
                        {
                            list = listeners;           // only specific listeners
                        }
                        else 
                        {
                            list = ListenerList.Empty;  // no listeners at all 
                        } 
                    }
                    else 
                    {
                        if (listeners != null)
                        {
                            // there are both specific and generic listeners - 
                            // combine the two lists.
                            list = new ListenerList(listeners.Count + genericListeners.Count); 
                            for (int i=0, n=listeners.Count; i

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK