// listen for changes to a property
        internal void RegisterForChanges(object item, PropertyDescriptor pd, DataBindEngine engine)
        {
            // lazy creation of the cache
            if (_table == null)
            {
                _table = new HybridDictionary();
            }

            ValueTableKey key   = new ValueTableKey(item, pd);
            object        value = _table[key];

            if (value == null)
            {
                // new entry needed - add a listener
                INotifyPropertyChanged inpc = item as INotifyPropertyChanged;
                if (inpc != null)
                {
                    PropertyChangedEventManager.AddHandler(inpc, OnPropertyChanged, pd.Name);
                }
                else
                {
                    ValueChangedEventManager.AddHandler(item, OnValueChanged, pd);
                }
            }
        }
        // invalidate (remove) a cache entry.  Called when the source raises a change event.
        void InvalidateCache(object item, PropertyDescriptor pd)
        {
            // ignore changes to special XLinq PD's - leave our interposed object in the cache
            if (SystemXmlLinqHelper.IsXLinqCollectionProperty(pd))
            {
                return;
            }

            ValueTableKey key = new ValueTableKey(item, pd);

            _table.Remove(key);
        }
        // return all the properties registered for the given item
        IEnumerable <PropertyDescriptor> GetPropertiesForItem(object item)
        {
            List <PropertyDescriptor> result = new List <PropertyDescriptor>();

            foreach (DictionaryEntry de in _table)
            {
                ValueTableKey key = (ValueTableKey)de.Key;
                if (Object.Equals(item, key.Item))
                {
                    result.Add(key.PropertyDescriptor);
                }
            }

            return(result);
        }
        // remove stale entries from the table
        internal bool Purge()
        {
            if (_table == null)
            {
                return(false);
            }

            // first see if there are any stale entries.  No sense allocating
            // storage if there's nothing to do.
            bool        isPurgeNeeded = false;
            ICollection keys          = _table.Keys;

            foreach (ValueTableKey key in keys)
            {
                if (key.IsStale)
                {
                    isPurgeNeeded = true;
                    break;
                }
            }

            // if the purge is needed, copy the keys and purge the
            // stale entries.  The copy avoids deletion out from under the
            // key collection.
            if (isPurgeNeeded)
            {
                ValueTableKey[] localKeys = new ValueTableKey[keys.Count];
                keys.CopyTo(localKeys, 0);

                for (int i = localKeys.Length - 1; i >= 0; --i)
                {
                    if (localKeys[i].IsStale)
                    {
                        _table.Remove(localKeys[i]);
                    }
                }
            }

            return(isPurgeNeeded);   // return true if something happened
        }
            public override bool Equals(object o)
            {
                if (o == this)
                {
                    return(true);    // this allows deletion of stale keys
                }
                ValueTableKey that = o as ValueTableKey;

                if (that != null)
                {
                    object             item       = this.Item;
                    PropertyDescriptor descriptor = this.PropertyDescriptor;
                    if (item == null || descriptor == null)
                    {
                        return(false);   // a stale key matches nothing (except itself)
                    }
                    return(this._hashCode == that._hashCode &&
                           Object.Equals(item, that.Item) &&
                           Object.Equals(descriptor, that.PropertyDescriptor));
                }

                return(false);   // this doesn't match a non-ValueTableKey
            }
        // retrieve the value, using the cache if necessary
        internal object GetValue(object item, PropertyDescriptor pd, bool indexerIsNext)
        {
            if (!ShouldCache(item, pd))
            {
                // normal case - just get the value the old-fashioned way
                return(pd.GetValue(item));
            }
            else
            {
                // lazy creation of the cache
                if (_table == null)
                {
                    _table = new HybridDictionary();
                }

                // look up the value in the cache
                bool          isXLinqCollectionProperty = SystemXmlLinqHelper.IsXLinqCollectionProperty(pd);
                ValueTableKey key   = new ValueTableKey(item, pd);
                object        value = _table[key];

                // if there's no entry, fetch the value and cache it
                if (value == null)
                {
                    if (isXLinqCollectionProperty)
                    {
                        // interpose our own value for special XLinq properties
                        value = new XDeferredAxisSource(item, pd);
                    }
                    else
                    {
                        value = pd.GetValue(item);
                    }

                    if (value == null)
                    {
                        value = CachedNull;     // distinguish a null value from no entry
                    }

                    _table[key] = value;
                }

                // decode null, if necessary
                if (value == CachedNull)
                {
                    value = null;
                }
                else if (isXLinqCollectionProperty && !indexerIsNext)
                {
                    // The XLinq properties need special help.  When the path
                    // contains "Elements[Foo]", we should return the interposed
                    // XDeferredAxisSource;  the path worker will then call the XDAS's
                    // indexer with argument "Foo", and obtain the desired
                    // ObservableCollection.  But when the path contains "Elements"
                    // with no indexer, we should return an ObservableCollection
                    // corresponding to the full set of children.
                    // [All this applies to "Descendants" as well.]
                    XDeferredAxisSource xdas = (XDeferredAxisSource)value;
                    value = xdas.FullCollection;
                }

                return(value);
            }
        }
Esempio n. 7
0
        // retrieve the value, using the cache if necessary
        internal object GetValue(object item, PropertyDescriptor pd, bool indexerIsNext)
        {
            if (!ShouldCache(item, pd))
            {
                // normal case - just get the value the old-fashioned way
                return(pd.GetValue(item));
            }
            else
            {
                // lazy creation of the cache
                if (_table == null)
                {
                    _table = new HybridDictionary();
                }

                // look up the value in the cache
                bool          isXLinqCollectionProperty = SystemXmlLinqHelper.IsXLinqCollectionProperty(pd);
                ValueTableKey key   = new ValueTableKey(item, pd);
                object        value = _table[key];

                Action FetchAndCacheValue = () =>
                {
                    // if there's no entry, fetch the value and cache it
                    if (value == null)
                    {
                        if (SystemDataHelper.IsDataSetCollectionProperty(pd))
                        {
                            // intercept GetValue calls for certain ADO properties
                            value = SystemDataHelper.GetValue(item, pd, !FrameworkAppContextSwitches.DoNotUseFollowParentWhenBindingToADODataRelation);
                        }
                        else if (isXLinqCollectionProperty)
                        {
                            // interpose our own value for special XLinq properties
                            value = new XDeferredAxisSource(item, pd);
                        }
                        else
                        {
                            value = pd.GetValue(item);
                        }

                        if (value == null)
                        {
                            value = CachedNull;     // distinguish a null value from no entry
                        }

                        // for DataSet properties, store a weak reference to avoid
                        // a memory leak
                        if (SystemDataHelper.IsDataSetCollectionProperty(pd))
                        {
                            value = new WeakReference(value);
                        }

                        _table[key] = value;
                    }

                    if (SystemDataHelper.IsDataSetCollectionProperty(pd))
                    {
                        // we stored a weak reference - decode it now
                        WeakReference wr = value as WeakReference;
                        if (wr != null)
                        {
                            value = wr.Target;
                        }
                    }
                };

                FetchAndCacheValue();

                if (value == null)
                {
                    // we can only get here if we cached a weak reference
                    // whose target has since been GC'd.  Repeating the call
                    // will refetch the value from the item, and is guaranteed
                    // to set value to non-null.
                    FetchAndCacheValue();
                }

                // decode null, if necessary
                if (value == CachedNull)
                {
                    value = null;
                }
                else if (isXLinqCollectionProperty && !indexerIsNext)
                {
                    // The XLinq properties need special help.  When the path
                    // contains "Elements[Foo]", we should return the interposed
                    // XDeferredAxisSource;  the path worker will then call the XDAS's
                    // indexer with argument "Foo", and obtain the desired
                    // ObservableCollection.  But when the path contains "Elements"
                    // with no indexer, we should return an ObservableCollection
                    // corresponding to the full set of children.
                    // [All this applies to "Descendants" as well.]
                    XDeferredAxisSource xdas = (XDeferredAxisSource)value;
                    value = xdas.FullCollection;
                }

                return(value);
            }
        }
Esempio n. 8
0
        // retrieve the value, using the cache if necessary
        internal object GetValue(object item, PropertyDescriptor pd, bool indexerIsNext)
        {
            if (!ShouldCache(item, pd))
            {
                // normal case - just get the value the old-fashioned way
                return pd.GetValue(item);
            }
            else
            {
                // lazy creation of the cache
                if (_table == null)
                {
                    _table = new HybridDictionary();
                }

                // look up the value in the cache
                bool isXLinqCollectionProperty = SystemXmlLinqHelper.IsXLinqCollectionProperty(pd);
                ValueTableKey key = new ValueTableKey(item, pd);
                object value = _table[key];

                // if there's no entry, fetch the value and cache it
                if (value == null)
                {
                    if (isXLinqCollectionProperty)
                    {
                        // interpose our own value for special XLinq properties
                        value = new XDeferredAxisSource(item, pd);
                    }
                    else
                    {
                        value = pd.GetValue(item);
                    }

                    if (value == null)
                    {
                        value = CachedNull;     // distinguish a null value from no entry
                    }

                    _table[key] = value;
                }

                // decode null, if necessary
                if (value == CachedNull)
                {
                    value = null;
                }
                else if (isXLinqCollectionProperty && !indexerIsNext)
                {
                    // The XLinq properties need special help.  When the path
                    // contains "Elements[Foo]", we should return the interposed
                    // XDeferredAxisSource;  the path worker will then call the XDAS's
                    // indexer with argument "Foo", and obtain the desired
                    // ObservableCollection.  But when the path contains "Elements"
                    // with no indexer, we should return an ObservableCollection
                    // corresponding to the full set of children.
                    // [All this applies to "Descendants" as well.]
                    XDeferredAxisSource xdas = (XDeferredAxisSource)value;
                    value = xdas.FullCollection;
                }

                return value;
            }
        }
Esempio n. 9
0
        // remove stale entries from the table
        internal bool Purge()
        {
            if (_table == null)
                return false;

            // first see if there are any stale entries.  No sense allocating
            // storage if there's nothing to do.
            bool isPurgeNeeded = false;
            ICollection keys = _table.Keys;
            foreach (ValueTableKey key in keys)
            {
                if (key.IsStale)
                {
                    isPurgeNeeded = true;
                    break;
                }
            }

            // if the purge is needed, copy the keys and purge the
            // stale entries.  The copy avoids deletion out from under the
            // key collection.
            if (isPurgeNeeded)
            {
                ValueTableKey[] localKeys = new ValueTableKey[keys.Count];
                keys.CopyTo(localKeys, 0);

                for (int i=localKeys.Length-1;  i >= 0;  --i)
                {
                    if (localKeys[i].IsStale)
                    {
                        _table.Remove(localKeys[i]);
                    }
                }
            }

            return isPurgeNeeded;   // return true if something happened
        }
Esempio n. 10
0
        // invalidate (remove) a cache entry.  Called when the source raises a change event.
        void InvalidateCache(object item, PropertyDescriptor pd)
        {
            // ignore changes to special XLinq PD's - leave our interposed object in the cache
            if (SystemXmlLinqHelper.IsXLinqCollectionProperty(pd))
                return;

            ValueTableKey key = new ValueTableKey(item, pd);
            _table.Remove(key);
        }
Esempio n. 11
0
        // listen for changes to a property
        internal void RegisterForChanges(object item, PropertyDescriptor pd, DataBindEngine engine)
        {
            // lazy creation of the cache
            if (_table == null)
            {
                _table = new HybridDictionary();
            }

            ValueTableKey key = new ValueTableKey(item, pd);
            object value = _table[key];

            if (value == null)
            {
                // new entry needed - add a listener
                INotifyPropertyChanged inpc = item as INotifyPropertyChanged;
                if (inpc != null)
                {
                    PropertyChangedEventManager.AddHandler(inpc, OnPropertyChanged, pd.Name);
                }
                else
                {
                    ValueChangedEventManager.AddHandler(item, OnValueChanged, pd);
                }
            }
        }