ValueChangedEventManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / MS / Internal / Data / ValueChangedEventManager.cs / 1 / ValueChangedEventManager.cs

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

/***************************************************************************\
    The "value changed" pattern doesn't use events.  To listen for changes
    in a property, a client first obtains the PropertyDescriptor for that 
    property, then calls the AddValueChanged method to register a callback.
    The arguments to the callback don't say which property has changed(!). 
 
    The standard manager implementation doesn't work for this.  Hence this
    manager overrides and/or ignores the base class methods. 

    This manager keeps a table of records, indexed by PropertyDescriptor.
    Each record holds the following information:
        PropertyDescriptor 
        Callback method
        ListenerList 
    In short, there's a separate callback method for each property.  That 
    method knows which property has changed, and can ask the manager to
    deliver the "event" to the listeners that are interested in that property. 
\****************************************************************************/

using System;
using System.Collections;               // ICollection 
using System.Collections.Specialized;   // HybridDictionary
using System.ComponentModel;            // PropertyDescriptor 
using System.Diagnostics;               // Debug 
using System.Windows;                   // WeakEventManager
 
namespace MS.Internal.Data
{
    /// 
    /// Manager for the object.ValueChanged event. 
    /// 
    internal class ValueChangedEventManager : WeakEventManager 
    { 
        #region Constructors
 
        //
        //  Constructors
        //
 
        private ValueChangedEventManager()
        { 
        } 

        #endregion Constructors 

        #region Public Methods

        // 
        //  Public Methods
        // 
 
        /// 
        /// Add a listener to the given source's event. 
        /// 
        public static void AddListener(object source, IWeakEventListener listener, PropertyDescriptor pd)
        {
            CurrentManager.PrivateAddListener(source, listener, pd); 
        }
 
        ///  
        /// Remove a listener to the given source's event.
        ///  
        public static void RemoveListener(object source, IWeakEventListener listener, PropertyDescriptor pd)
        {
            CurrentManager.PrivateRemoveListener(source, listener, pd);
        } 

        #endregion Public Methods 
 
        #region Protected Methods
 
        //
        //  Protected Methods
        //
 
        // The next two methods need to be defined, but they're never called.
 
        ///  
        /// Listen to the given source for the event.
        ///  
        protected override void StartListening(object source)
        {
        }
 
        /// 
        /// Stop listening to the given source for the event. 
        ///  
        protected override void StopListening(object source)
        { 
        }

        /// 
        /// 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; 

            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;
        }
 
        #endregion Protected Methods
 
        #region Private Properties 

        // 
        //  Private Properties
        //

        // get the event manager for the current thread 
        private static ValueChangedEventManager CurrentManager
        { 
            get 
            {
                Type managerType = typeof(ValueChangedEventManager); 
                ValueChangedEventManager manager = (ValueChangedEventManager)GetCurrentManager(managerType);

                // at first use, create and register a new manager
                if (manager == null) 
                {
                    manager = new ValueChangedEventManager(); 
                    SetCurrentManager(managerType, manager); 
                }
 
                return manager;
            }
        }
 
        #endregion Private Properties
 
        #region Private Methods 

        // 
        //  Private Methods
        //

        // Add a listener to the given property 
        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(); 
            }
        }

        // Remove a listener to the named property (empty means "any property") 
        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);
                    } 
                } 
            }
        } 

        #endregion Private Methods

        #region ValueChangedRecord 

        private class ValueChangedRecord 
        { 
            public ValueChangedRecord(ValueChangedEventManager manager, object source, PropertyDescriptor pd)
            { 
                _manager = manager;
                _source.Target = source;
                _pd = pd;
                _eventArgs = new ValueChangedEventArgs(pd); 

                pd.AddValueChanged(source, new EventHandler(OnValueChanged)); 
            } 

            public bool IsEmpty 
            {
                get { return _listeners.IsEmpty; }
            }
 
            // add a listener
            public void Add(IWeakEventListener listener) 
            { 
                // make sure list is ready for writing
                ListenerList.PrepareForWriting(ref _listeners); 

                _listeners.Add(listener);
            }
 
            // remove a listener
            public void Remove(IWeakEventListener listener) 
            { 
                // make sure list is ready for writing
                ListenerList.PrepareForWriting(ref _listeners); 

                _listeners.Remove(listener);

                // when the last listener goes away, remove the callback 
                if (_listeners.IsEmpty)
                { 
                    StopListening(); 
                }
            } 

            // purge dead entries
            public bool Purge()
            { 
                ListenerList.PrepareForWriting(ref _listeners);
                return _listeners.Purge(); 
            } 

            // remove the callback from the PropertyDescriptor 
            public void StopListening()
            {
                object source = _source.Target;
                if (source != null) 
                {
                    _source.Target = null; 
                    _pd.RemoveValueChanged(source, new EventHandler(OnValueChanged)); 
                }
            } 

            // forward the ValueChanged event to the listeners
            private void OnValueChanged(object sender, EventArgs e)
            { 
                // mark the list of listeners "in use"
                using (_manager.ReadLock) 
                { 
                    _listeners.BeginUse();
                } 

                // deliver the event, being sure to undo the effect of BeginUse().
                try
                { 
                    _manager.DeliverEventToList(sender, _eventArgs, _listeners);
                } 
                finally 
                {
                    _listeners.EndUse(); 
                }
            }

            PropertyDescriptor          _pd; 
            ValueChangedEventManager    _manager;
            WeakReference               _source = new WeakReference(null); 
            ListenerList                _listeners = new ListenerList(); 
            ValueChangedEventArgs       _eventArgs;
        } 

        #endregion ValueChangedRecord
    }
 
    #region ValueChangedEventArgs
 
    internal class ValueChangedEventArgs : EventArgs 
    {
        internal ValueChangedEventArgs(PropertyDescriptor pd) 
        {
            _pd = pd;
        }
 
        internal PropertyDescriptor PropertyDescriptor
        { 
            get { return _pd; } 
        }
 
        private PropertyDescriptor _pd;
    }
    #endregion ValueChangedEventArgs
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

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