Beispiel #1
0
            public ListenerList GetListenerList(string propertyName)
            {
                ListenerList list;

                if (!String.IsNullOrEmpty(propertyName))
                {
                    // source has changed a particular property.  Notify targets
                    // who are listening either for this property or for all properties.
                    PropertyRecord pr = (PropertyRecord)_dict[propertyName];
                    ListenerList <PropertyChangedEventArgs> listeners = (pr == null) ? null : pr.List;
                    PropertyRecord genericRecord = (PropertyRecord)_dict[String.Empty];
                    ListenerList <PropertyChangedEventArgs> genericListeners = (genericRecord == null) ? null : genericRecord.List;

                    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 <PropertyChangedEventArgs>(listeners.Count + genericListeners.Count);
                            for (int i = 0, n = listeners.Count; i < n; ++i)
                            {
                                list.Add(listeners[i]);
                            }
                            for (int i = 0, n = genericListeners.Count; i < n; ++i)
                            {
                                list.Add(genericListeners[i]);
                            }
                        }
                        else
                        {
                            list = genericListeners;    // only generic listeners
                        }
                    }
                }
                else
                {
                    // source has changed all properties.  Notify all targets.
                    // Use previously calculated combined list, if available.
                    PropertyRecord pr = (PropertyRecord)_dict[AllListenersKey];
                    ListenerList <PropertyChangedEventArgs> pcList = (pr == null) ? null : pr.List;

                    if (pcList == null)
                    {
                        // make one pass to compute the size of the combined list.
                        // This avoids expensive reallocations.
                        int size = 0;
                        foreach (DictionaryEntry de in _dict)
                        {
                            Debug.Assert((String)de.Key != AllListenersKey, "special key should not appear");
                            size += ((PropertyRecord)de.Value).List.Count;
                        }

                        // create the combined list
                        pcList = new ListenerList <PropertyChangedEventArgs>(size);

                        // fill in the combined list
                        foreach (DictionaryEntry de in _dict)
                        {
                            ListenerList listeners = ((PropertyRecord)de.Value).List;
                            for (int i = 0, n = listeners.Count; i < n; ++i)
                            {
                                pcList.Add(listeners.GetListener(i));
                            }
                        }

                        // save the result for future use (see below)
                        _proposedAllListenersList = pcList;
                    }

                    list = pcList;
                }

                return(list);
            }
Beispiel #2
0
        // 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 <PropertyChangedEventArgs> listeners        = (ListenerList <PropertyChangedEventArgs>)dict[propertyName];
                    ListenerList <PropertyChangedEventArgs> genericListeners = (ListenerList <PropertyChangedEventArgs>)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 <PropertyChangedEventArgs>(listeners.Count + genericListeners.Count);
                            for (int i = 0, n = listeners.Count; i < n; ++i)
                            {
                                list.Add(listeners.GetListener(i));
                            }
                            for (int i = 0, n = genericListeners.Count; i < n; ++i)
                            {
                                list.Add(genericListeners.GetListener(i));
                            }
                        }
                        else
                        {
                            list = genericListeners;    // only generic listeners
                        }
                    }
                }
                else
                {
                    // source has changed all properties.  Notify all targets.
                    // Use previously calculated combined list, if available.
                    list = (ListenerList)dict[AllListenersKey];

                    if (list == null)
                    {
                        // make one pass to compute the size of the combined list.
                        // This avoids expensive reallocations.
                        int size = 0;
                        foreach (DictionaryEntry de in dict)
                        {
                            Debug.Assert((String)de.Key != AllListenersKey, "special key should not appear");
                            size += ((ListenerList)de.Value).Count;
                        }

                        // create the combined list
                        list = new ListenerList <PropertyChangedEventArgs>(size);

                        // fill in the combined list
                        foreach (DictionaryEntry de in dict)
                        {
                            ListenerList listeners = ((ListenerList)de.Value);
                            for (int i = 0, n = listeners.Count; i < n; ++i)
                            {
                                list.Add(listeners.GetListener(i));
                            }
                        }

                        // save the result for future use (see below)
                        _proposedAllListenersList = list;
                    }
                }

                // mark the list "in use", even outside the read lock,
                // so that any writers will know not to modify it (they'll
                // modify a clone intead).
                list.BeginUse();
            }

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

            // if we calculated an AllListeners list, we should now try to store
            // it in the dictionary so it can be used in the future.  This must be
            // done under a WriteLock - which is why we didn't do it immediately.
            if (_proposedAllListenersList == list)
            {
                using (WriteLock)
                {
                    // test again, in case another thread changed _proposedAllListersList.
                    if (_proposedAllListenersList == list)
                    {
                        HybridDictionary dict = (HybridDictionary)this[sender];
                        if (dict != null)
                        {
                            dict[AllListenersKey] = list;
                        }

                        _proposedAllListenersList = null;
                    }

                    // Another thread could have changed _proposedAllListersList
                    // since we set it (earlier in this method), either
                    // because it calculated a new one while handling a PropertyChanged(""),
                    // or because it added/removed/purged a listener.
                    // In that case, we will simply abandon our proposed list and we'll
                    // have to compute it again the next time.  But that only happens
                    // if there's thread contention.  It's not worth doing something
                    // more complicated just for that case.
                }
            }
        }