File: System\Windows\ResourceDictionary.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
/***************************************************************************\
*
*
*  Dictionary that holds Resources for Framework components.
*
*
\***************************************************************************/
using System.IO;
using System.Net;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows.Threading;
using System.Windows.Media;
using System.Windows.Diagnostics;
 
using MS.Internal;
using MS.Internal.Utility;
using MS.Internal.AppModel;
using System.Xaml;
using System.Windows.Baml2006;
using System.Windows.Markup;
 
namespace System.Windows
{
    /// <summary>
    ///     Dictionary that holds Resources for Framework components.
    /// </summary>
    [Localizability(LocalizationCategory.Ignore)]
    [Ambient]
    [UsableDuringInitialization(true)]
    public class ResourceDictionary : IDictionary, ISupportInitialize, System.Windows.Markup.IUriContext, System.Windows.Markup.INameScope
    {
        #region Constructor
 
        /// <summary>
        ///     Constructor for ResourceDictionary
        /// </summary>
        public ResourceDictionary()
        {
            _baseDictionary = new Hashtable();
            IsThemeDictionary = SystemResources.IsSystemResourcesParsing;
        }
 
        static ResourceDictionary()
        {
            DummyInheritanceContext.DetachFromDispatcher();
        }
 
        #endregion Constructor
 
        #region PublicAPIs
 
        /// <summary>
        ///     Copies the dictionary's elements to a one-dimensional
        ///     Array instance at the specified index.
        /// </summary>
        /// <param name="array">
        ///     The one-dimensional Array that is the destination of the
        ///     DictionaryEntry objects copied from Hashtable. The Array
        ///     must have zero-based indexing.
        /// </param>
        /// <param name="arrayIndex">
        ///     The zero-based index in array at which copying begins.
        /// </param>
        public void CopyTo(DictionaryEntry[] array, int arrayIndex)
        {
            if (CanBeAccessedAcrossThreads)
            {
                lock(((ICollection)this).SyncRoot)
                {
                    CopyToWithoutLock(array, arrayIndex);
                }
            }
            else
            {
                CopyToWithoutLock(array, arrayIndex);
            }
        }
 
        private void CopyToWithoutLock(DictionaryEntry[] array, int arrayIndex)
        {
            ArgumentNullException.ThrowIfNull(array);
 
            _baseDictionary.CopyTo(array, arrayIndex);
 
            int length = arrayIndex + Count;
            for (int i = arrayIndex; i < length; i++)
            {
                DictionaryEntry entry = array[i];
                object value = entry.Value;
                bool canCache;
                OnGettingValuePrivate(entry.Key, ref value, out canCache);
                entry.Value = value; // refresh the entry value in case it was changed in the previous call
            }
        }
 
        // This is set when the RD is loaded from unsafe xps doc. This will be checked while creating reader for RD source.
        internal bool IsUnsafe { get; set; }
 
        ///<summary>
        ///     List of ResourceDictionaries merged into this Resource Dictionary
        ///</summary>
        public Collection<ResourceDictionary> MergedDictionaries
        {
            get
            {
                if (_mergedDictionaries == null)
                {
                    _mergedDictionaries = new ResourceDictionaryCollection(this);
                    _mergedDictionaries.CollectionChanged += OnMergedDictionariesChanged;
                }
 
                return _mergedDictionaries;
            }
        }
 
        ///<summary>
        ///     Uri to load this resource from, it will clear the current state of the ResourceDictionary
        ///</summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Uri Source
        {
            get
            {
                return _source;
            }
            set
            {
                if (value == null || String.IsNullOrEmpty(value.OriginalString))
                {
                    throw new ArgumentException(SR.Format(SR.ResourceDictionaryLoadFromFailure, value == null ? "''" : value.ToString()));
                }
 
                ResourceDictionaryDiagnostics.RemoveResourceDictionaryForUri(_source, this);
 
                ResourceDictionarySourceUriWrapper uriWrapper = value as ResourceDictionarySourceUriWrapper;
 
                Uri sourceUri;
 
                // If the Uri we received is a ResourceDictionarySourceUriWrapper it means
                // that it is being passed down by the Baml parsing code, and it is trying to give us more
                // information to avoid possible ambiguities in assembly resolving. Use the VersionedUri
                // to resolve, and the set _source to the OriginalUri so we don't change the return of Source property.
                // The versioned Uri is not stored, if the version info is needed while debugging, once this method
                // returns _reader should be set, from there BamlSchemaContext.LocalAssembly contains the version info.
                if (uriWrapper == null)
                {
                    _source = value;
                    sourceUri = _source;
                }
                else
                {
                    _source = uriWrapper.OriginalUri;
                    sourceUri = uriWrapper.VersionedUri;
                }
 
                Clear();
 
 
                Uri uri = BindUriHelper.GetResolvedUri(_baseUri, sourceUri);
 
                WebRequest request = WpfWebRequestHelper.CreateRequest(uri);
                WpfWebRequestHelper.ConfigCachePolicy(request, false);
                ContentType contentType = null;
                Stream s = null;
 
                try
                {
                     s = WpfWebRequestHelper.GetResponseStream(request, out contentType);
                }
                catch (System.IO.IOException)
                {
                    if (IsSourcedFromThemeDictionary)
                    {
                        switch (_fallbackState)
                        {
                            case FallbackState.Classic:
                                {
                                    _fallbackState = FallbackState.Generic;
                                    Uri classicResourceUri = ThemeDictionaryExtension.GenerateFallbackUri(this, SystemResources.ClassicResourceName);
                                    Debug.Assert(classicResourceUri != null);
 
                                    Source = classicResourceUri;
                                    // After this recursive call has returned we are sure
                                    // that we have tried all fallback paths and so now
                                    // reset the _fallbackState
                                    _fallbackState = FallbackState.Classic;
                                }
                                break;
                            case FallbackState.Generic:
                                {
                                    _fallbackState = FallbackState.None;
                                    Uri genericResourceUri = ThemeDictionaryExtension.GenerateFallbackUri(this, SystemResources.GenericResourceName);
 
                                    Debug.Assert(genericResourceUri != null);
                                    Source = genericResourceUri;
 
                                }
                                break;
                        }
                        return;
                    }
                    else
                    {
                        throw;
                    }
                }
 
                // MimeObjectFactory.GetObjectAndCloseStream will try to find the object converter basing on the mime type.
                // It can be a sync/async converter. It's the converter's responsiblity to close the stream.
                // If it fails to find a convert, this call will return null.
                System.Windows.Markup.XamlReader asyncObjectConverter;
                ResourceDictionary loadedRD = MimeObjectFactory.GetObjectAndCloseStreamCore(s, contentType, uri, false, false, false /*allowAsync*/, false /*isJournalNavigation*/, out asyncObjectConverter, IsUnsafe)
                                            as ResourceDictionary;
 
                if (loadedRD == null)
                {
                    throw new InvalidOperationException(SR.Format(SR.ResourceDictionaryLoadFromFailure, _source.ToString()));
                }
 
                // ReferenceCopy all the key-value pairs in the _baseDictionary
                _baseDictionary = loadedRD._baseDictionary;
 
                // ReferenceCopy all the entries in the MergedDictionaries collection
                _mergedDictionaries = loadedRD._mergedDictionaries;
 
                // ReferenceCopy all of the deferred content state
                CopyDeferredContentFrom(loadedRD);
 
                // Take over the deferred resource references
                MoveDeferredResourceReferencesFrom(loadedRD);
 
                // Copy over the HasImplicitStyles flag
                HasImplicitStyles = loadedRD.HasImplicitStyles;
 
                // Copy over the HasImplicitDataTemplates flag
                HasImplicitDataTemplates = loadedRD.HasImplicitDataTemplates;
 
                // Copy over the InvalidatesImplicitDataTemplateResources flag
                InvalidatesImplicitDataTemplateResources = loadedRD.InvalidatesImplicitDataTemplateResources;
 
                // Set inheritance context on the copied values
                if (InheritanceContext != null)
                {
                    AddInheritanceContextToValues();
                }
 
                // Propagate parent owners to each of the acquired merged dictionaries
                if (_mergedDictionaries != null)
                {
                    for (int i = 0; i < _mergedDictionaries.Count; i++)
                    {
                        PropagateParentOwners(_mergedDictionaries[i]);
                    }
                }
 
                ResourceDictionaryDiagnostics.AddResourceDictionaryForUri(uri, this);
 
                if (!IsInitializePending)
                {
                    // Fire Invalidations for the changes made by asigning a new Source
                    NotifyOwners(new ResourcesChangeInfo(null, this));
                }
            }
        }
 
        #region INameScope
        /// <summary>
        /// Registers the name - element combination
        /// </summary>
        /// <param name="name">name of the element</param>
        /// <param name="scopedElement">Element where name is defined</param>
        public void RegisterName(string name, object scopedElement)
        {
            throw new NotSupportedException(SR.NamesNotSupportedInsideResourceDictionary);
        }
 
        /// <summary>
        /// Unregisters the name - element combination
        /// </summary>
        /// <param name="name">Name of the element</param>
        public void UnregisterName(string name)
        {
            // Do Nothing as Names cannot be registered on ResourceDictionary
        }
 
        /// <summary>
        /// Find the element given name
        /// </summary>
        /// <param name="name">Name of the element</param>
        /// <returns>null always</returns>
        public object FindName(string name)
        {
            return null;
        }
 
        #endregion INameScope
 
        #region IUriContext
 
        /// <summary>
        ///     Accessor for the base uri of the ResourceDictionary
        /// </summary>
        Uri System.Windows.Markup.IUriContext.BaseUri
        {
            get
            {
                return  _baseUri;
            }
            set
            {
                _baseUri = value;
            }
        }
 
        #endregion IUriContext
 
        #endregion PublicAPIs
 
        #region IDictionary
 
        /// <summary>
        ///     Gets a value indicating whether the IDictionary has a fixed size.
        /// </summary>
        public bool IsFixedSize
        {
            get { return _baseDictionary.IsFixedSize; }
        }
 
        /// <summary>
        ///     Gets a value indicating whether the ResourceDictionary is read-only.
        /// </summary>
        public bool IsReadOnly
        {
            get { return ReadPrivateFlag(PrivateFlags.IsReadOnly); }
            internal set
            {
                WritePrivateFlag(PrivateFlags.IsReadOnly, value);
 
                if (value == true)
                {
                    // Seal all the styles and templates in this dictionary
                    SealValues();
                }
 
                // Set all the merged resource dictionaries as ReadOnly
                if (_mergedDictionaries != null)
                {
                    for (int i = 0; i < _mergedDictionaries.Count; i++)
                    {
                        _mergedDictionaries[i].IsReadOnly = value;
                    }
                }
            }
        }
 
        /// <summary>
        ///     Gets or sets a value indicating whether the invalidations fired
        ///     by the ResourceDictionary when an implicit data template resource
        ///     changes will cause ContentPresenters to re-evaluate their choice
        ///     of template.
        /// </summary>
        [DefaultValue(false)]
        public bool InvalidatesImplicitDataTemplateResources
        {
            get { return ReadPrivateFlag(PrivateFlags.InvalidatesImplicitDataTemplateResources); }
            set { WritePrivateFlag(PrivateFlags.InvalidatesImplicitDataTemplateResources, value); }
        }
 
        /// <summary>
        ///     Gets or sets the value associated with the specified key.
        /// </summary>
        /// <remarks>
        ///     Fire Invalidations only for changes made after the Init Phase
        ///     If the key is not found on this ResourceDictionary, it will look on any MergedDictionaries for it
        /// </remarks>
        public object this[object key]
        {
            get
            {
                bool canCache;
                return GetValue(key, out canCache);
            }
 
            set
            {
                // Seal styles and templates within App and Theme dictionary
                SealValue(value);
 
                if (CanBeAccessedAcrossThreads)
                {
                    lock(((ICollection)this).SyncRoot)
                    {
                        SetValueWithoutLock(key, value);
                    }
                }
                else
                {
                    SetValueWithoutLock(key, value);
                }
            }
        }
 
        // This should only be called in the deferred BAML loading scenario.  We
        // cache all the data that we need away and then get rid of the actual object.
        // No one needs to actually get this property so we're returning null.  This
        // property has to be public since the XAML parser cannot set this internal
        // property in this scenario.
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public DeferrableContent DeferrableContent
        {
            get
            {
                return null;
            }
            set
            {
                this.SetDeferrableContent(value);
            }
        }
 
        private void SetValueWithoutLock(object key, object value)
        {
            if (IsReadOnly)
            {
                throw new InvalidOperationException(SR.ResourceDictionaryIsReadOnly);
            }
 
            object oldValue = _baseDictionary[key];
 
            if (oldValue != value)
            {
                // We need to validate all the deferred references that refer
                // to the old resource before we overwrite it.
                ValidateDeferredResourceReferences(key);
 
                if( TraceResourceDictionary.IsEnabled )
                {
                    TraceResourceDictionary.Trace( TraceEventType.Start,
                                                   TraceResourceDictionary.AddResource,
                                                   this,
                                                   key,
                                                   value );
                }
 
 
                _baseDictionary[key] = value;
 
                // Update the HasImplicitStyles flag
                UpdateHasImplicitStyles(key);
 
                // Update the HasImplicitDataTemplates flag
                UpdateHasImplicitDataTemplates(key);
 
                // Notify owners of the change and fire invalidate if already initialized
                NotifyOwners(new ResourcesChangeInfo(key));
 
                if( TraceResourceDictionary.IsEnabled )
                {
                    TraceResourceDictionary.Trace(
                                                  TraceEventType.Stop,
                                                  TraceResourceDictionary.AddResource,
                                                  this,
                                                  key,
                                                  value );
                }
 
 
            }
        }
 
        internal object GetValue(object key, out bool canCache)
        {
            if (CanBeAccessedAcrossThreads)
            {
                lock(((ICollection)this).SyncRoot)
                {
                    return GetValueWithoutLock(key, out canCache);
                }
            }
            else
            {
                return GetValueWithoutLock(key, out canCache);
            }
        }
 
        private object GetValueWithoutLock(object key, out bool canCache)
        {
            object value = _baseDictionary[key];
            if (value != null)
            {
                OnGettingValuePrivate(key, ref value, out canCache);
            }
            else
            {
                canCache = true;
 
                //Search for the value in the Merged Dictionaries
                if (_mergedDictionaries != null)
                {
                    for (int i = MergedDictionaries.Count - 1; (i > -1); i--)
                    {
                        // Note that MergedDictionaries collection can also contain null values
                        ResourceDictionary mergedDictionary = MergedDictionaries[i];
                        if (mergedDictionary != null)
                        {
                            value = mergedDictionary.GetValue(key, out canCache);
                            if (value != null)
                            {
                                break;
                            }
                        }
                    }
                }
            }
 
            return value;
        }
 
        // Gets the type of the value stored at the given key
        internal Type GetValueType(object key, out bool found)
        {
            found = false;
            Type valueType = null;
 
            object value = _baseDictionary[key];
            if (value != null)
            {
                found = true;
 
                KeyRecord keyRecord = value as KeyRecord;
                if (keyRecord != null)
                {
                    Debug.Assert(_numDefer > 0, "The stream was closed before all deferred content was loaded.");
                    valueType = GetTypeOfFirstObject(keyRecord);
                }
                else
                {
                    valueType = value.GetType();
                }
 
            }
            else
            {
                // Search for the value in the Merged Dictionaries
                if (_mergedDictionaries != null)
                {
                    for (int i = MergedDictionaries.Count - 1; (i > -1); i--)
                    {
                        // Note that MergedDictionaries collection can also contain null values
                        ResourceDictionary mergedDictionary = MergedDictionaries[i];
                        if (mergedDictionary != null)
                        {
                            valueType = mergedDictionary.GetValueType(key, out found);
                            if (found)
                            {
                                break;
                            }
                        }
                    }
                }
            }
 
            return valueType;
        }
 
        /// <summary>
        ///     Gets a copy of the ICollection containing the keys of the IDictionary.
        /// </summary>
        public ICollection Keys
        {
            get
            {
                object[] keysCollection = new object[Count];
                _baseDictionary.Keys.CopyTo(keysCollection, 0);
                return keysCollection;
            }
        }
 
        /// <summary>
        ///     Gets an ICollection containing the values in the Hashtable
        /// </summary>
        /// <value>An ICollection containing the values in the Hashtable</value>
        public ICollection Values
        {
            get
            {
                return new ResourceValuesCollection(this);
            }
        }
 
        /// <summary>
        ///     Adds an entry
        /// </summary>
        /// <remarks>
        ///     Fire Invalidations only for changes made after the Init Phase
        /// </remarks>
        public void Add(object key, object value)
        {
            // Seal styles and templates within App and Theme dictionary
            SealValue(value);
 
            if (CanBeAccessedAcrossThreads)
            {
                lock(((ICollection)this).SyncRoot)
                {
                    AddWithoutLock(key, value);
                }
            }
            else
            {
                AddWithoutLock(key, value);
            }
 
        }
 
        private void AddWithoutLock(object key, object value)
        {
            if (IsReadOnly)
            {
                throw new InvalidOperationException(SR.ResourceDictionaryIsReadOnly);
            }
 
            // invalid during a VisualTreeChanged event
            System.Windows.Diagnostics.VisualDiagnostics.VerifyVisualTreeChange(InheritanceContext);
 
            if( TraceResourceDictionary.IsEnabled )
            {
                TraceResourceDictionary.Trace( TraceEventType.Start,
                                               TraceResourceDictionary.AddResource,
                                               this,
                                               key,
                                               value );
            }
 
 
            _baseDictionary.Add(key, value);
 
            // Update the HasImplicitKey flag
            UpdateHasImplicitStyles(key);
 
            // Update the HasImplicitDataTemplates flag
            UpdateHasImplicitDataTemplates(key);
 
            // Notify owners of the change and fire invalidate if already initialized
            NotifyOwners(new ResourcesChangeInfo(key));
 
            if( TraceResourceDictionary.IsEnabled )
            {
                TraceResourceDictionary.Trace( TraceEventType.Stop,
                                               TraceResourceDictionary.AddResource,
                                               this,
                                               key,
                                               value );
            }
 
        }
 
        /// <summary>
        ///     Removes all elements from the IDictionary.
        /// </summary>
        public void Clear()
        {
            if (CanBeAccessedAcrossThreads)
            {
                lock(((ICollection)this).SyncRoot)
                {
                    ClearWithoutLock();
                }
            }
            else
            {
                ClearWithoutLock();
            }
        }
 
        private void ClearWithoutLock()
        {
            if (IsReadOnly)
            {
                throw new InvalidOperationException(SR.ResourceDictionaryIsReadOnly);
            }
 
            // invalid during a VisualTreeChanged event
            System.Windows.Diagnostics.VisualDiagnostics.VerifyVisualTreeChange(InheritanceContext);
 
            if (Count > 0)
            {
                // We need to validate all the deferred references that refer
                // to the old resource before we clear it.
                ValidateDeferredResourceReferences(null);
 
                // remove inheritance context from all values that got it from
                // this dictionary
                RemoveInheritanceContextFromValues();
 
                _baseDictionary.Clear();
 
                // Notify owners of the change and fire invalidate if already initialized
                NotifyOwners(ResourcesChangeInfo.CatastrophicDictionaryChangeInfo);
            }
        }
 
        /// <summary>
        ///     Determines whether the IDictionary contains an element with the specified key.
        ///     if the Key is not contained in this ResourceDictionary, it will check in the MergedDictionaries too
        /// </summary>
        public bool Contains(object key)
        {
            bool result = _baseDictionary.Contains(key);
 
            if (result)
            {
                KeyRecord keyRecord = _baseDictionary[key] as KeyRecord;
                if (keyRecord != null && _deferredLocationList.Contains(keyRecord))
                {
                    return false;
                }
            }
 
            //Search for the value in the Merged Dictionaries
            if (_mergedDictionaries != null)
            {
                for (int i = MergedDictionaries.Count - 1; (i > -1) && !result; i--)
                {
                    // Note that MergedDictionaries collection can also contain null values
                    ResourceDictionary mergedDictionary = MergedDictionaries[i];
                    if (mergedDictionary != null)
                    {
                        result = mergedDictionary.Contains(key);
                    }
                }
            }
            return result;
        }
 
        /// <summary>
        ///     Determines whether the IDictionary contains a BamlObjectFactory against the specified key.
        ///     if the Key is not contained in this ResourceDictionary, it will check in the MergedDictionaries too
        /// </summary>
        private bool ContainsBamlObjectFactory(object key)
        {
            return GetBamlObjectFactory(key) != null;
        }
 
        /// <summary>
        ///     Retrieves a KeyRecord from the IDictionary using the specified key.
        ///     If the Key is not contained in this ResourceDictionary, it will check in the MergedDictionaries too
        /// </summary>
        private KeyRecord GetBamlObjectFactory(object key)
        {
            if (_baseDictionary.Contains(key))
            {
                return _baseDictionary[key] as KeyRecord;
            }
 
            //Search for the value in the Merged Dictionaries
            if (_mergedDictionaries != null)
            {
                for (int i = MergedDictionaries.Count - 1; i > -1; i--)
                {
                    // Note that MergedDictionaries collection can also contain null values
                    ResourceDictionary mergedDictionary = MergedDictionaries[i];
                    if (mergedDictionary != null)
                    {
                        KeyRecord keyRecord = mergedDictionary.GetBamlObjectFactory(key);
                        if (keyRecord != null)
                        {
                            return keyRecord;
                        }
                    }
                }
            }
 
            return null;
        }
 
        /// <summary>
        ///     Returns an IDictionaryEnumerator that can iterate through the Hashtable
        /// </summary>
        /// <returns>An IDictionaryEnumerator for the Hashtable</returns>
        public IDictionaryEnumerator GetEnumerator()
        {
            return new ResourceDictionaryEnumerator(this);
        }
 
        /// <summary>
        ///     Removes an entry
        /// </summary>
        /// <remarks>
        ///     Fire Invalidations only for changes made after the Init Phase
        /// </remarks>
        public void Remove(object key)
        {
            if (CanBeAccessedAcrossThreads)
            {
                lock(((ICollection)this).SyncRoot)
                {
                    RemoveWithoutLock(key);
                }
            }
            else
            {
                RemoveWithoutLock(key);
            }
        }
 
        private void RemoveWithoutLock(object key)
        {
            if (IsReadOnly)
            {
                throw new InvalidOperationException(SR.ResourceDictionaryIsReadOnly);
            }
 
            // invalid during a VisualTreeChanged event
            System.Windows.Diagnostics.VisualDiagnostics.VerifyVisualTreeChange(InheritanceContext);
 
            // We need to validate all the deferred references that refer
            // to the old resource before we remove it.
            ValidateDeferredResourceReferences(key);
 
            // remove the inheritance context from the value, if it came from
            // this dictionary
            RemoveInheritanceContext(_baseDictionary[key]);
 
            _baseDictionary.Remove(key);
 
            // Notify owners of the change and fire invalidate if already initialized
            NotifyOwners(new ResourcesChangeInfo(key));
        }
 
        #endregion IDictionary
 
        #region ICollection
 
        /// <summary>
        ///     Gets the number of elements contained in the ICollection.
        /// </summary>
        public int Count
        {
            get { return _baseDictionary.Count; }
        }
 
        /// <summary>
        ///     Gets a value indicating whether access to the ICollection is synchronized (thread-safe).
        /// </summary>
        bool ICollection.IsSynchronized
        {
            get { return _baseDictionary.IsSynchronized; }
        }
 
        /// <summary>
        ///     Gets an object that can be used to synchronize access to the ICollection.
        /// </summary>
        object ICollection.SyncRoot
        {
            get
            {
                if (CanBeAccessedAcrossThreads)
                {
                    // Notice that we are acquiring the ThemeDictionaryLock. This
                    // is because the _parserContext used for template expansion
                    // shares data-structures such as the BamlMapTable and
                    // XamlTypeMapper with the parent ParserContext that was used
                    // to build the template in the first place. So if this template
                    // is from the App.Resources then the ParserContext that is used for
                    // loading deferred content in the app dictionary and the
                    // _parserContext used to load template content share the same
                    // instances of BamlMapTable and XamlTypeMapper. Hence we need to
                    // make sure that we lock on the same object inorder to serialize
                    // access to these data-structures in multi-threaded scenarios.
                    // Look at comment in Frameworktemplate.LoadContent to understand
                    // why we use the ThemeDictionaryLock for template expansion.
 
                    return SystemResources.ThemeDictionaryLock;
                }
                else
                {
                    return _baseDictionary.SyncRoot;
                }
            }
        }
 
        /// <summary>
        ///     Copies the dictionary's elements to a one-dimensional
        ///     Array instance at the specified index.
        /// </summary>
        /// <param name="array">
        ///     The one-dimensional Array that is the destination of the
        ///     DictionaryEntry objects copied from Hashtable. The Array
        ///     must have zero-based indexing.
        /// </param>
        /// <param name="arrayIndex">
        ///     The zero-based index in array at which copying begins.
        /// </param>
        void ICollection.CopyTo(Array array, int arrayIndex)
        {
            CopyTo(array as DictionaryEntry[], arrayIndex);
        }
 
        #endregion ICollection
 
        #region IEnumerable
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IDictionary)this).GetEnumerator();
        }
 
        #endregion IEnumerable
 
        #region ISupportInitialize
 
        /// <summary>
        ///     Mark the begining of the Init phase
        /// </summary>
        /// <remarks>
        ///     BeginInit and EndInit follow a transaction model. BeginInit marks the
        ///     dictionary uninitialized and EndInit marks it initialized.
        /// </remarks>
        public void BeginInit()
        {
            // Nested BeginInits on the same instance aren't permitted
            if (IsInitializePending)
            {
                throw new InvalidOperationException(SR.NestedBeginInitNotSupported);
            }
 
            IsInitializePending = true;
            IsInitialized = false;
        }
 
        /// <summary>
        ///     Fire Invalidation at the end of Init phase
        /// </summary>
        /// <remarks>
        ///     BeginInit and EndInit follow a transaction model. BeginInit marks the
        ///     dictionary uninitialized and EndInit marks it initialized.
        /// </remarks>
        public void EndInit()
        {
            // EndInit without a BeginInit isn't permitted
            if (!IsInitializePending)
            {
                throw new InvalidOperationException(SR.EndInitWithoutBeginInitNotSupported);
            }
            Debug.Assert(IsInitialized == false, "Dictionary should not be initialized when EndInit is called");
 
            IsInitializePending = false;
            IsInitialized = true;
 
            // Fire Invalidations collectively for all changes made during the Init Phase
            NotifyOwners(new ResourcesChangeInfo(null, this));
        }
 
        #endregion ISupportInitialize
 
        #region DeferContent
 
        private bool CanCache(KeyRecord keyRecord, object value)
        {
            if (keyRecord.SharedSet)
            {
                return keyRecord.Shared;
            }
            else
            {
                return true;
            }
        }
 
        private void OnGettingValuePrivate(object key, ref object value, out bool canCache)
        {
            // diagnostic agent may want to know when a StaticResource reference
            // resolves.  Do this before calling out to OnGettingValue, as that
            // can inflate deferred content and cause nested requests
            ResourceDictionaryDiagnostics.RecordLookupResult(key, this);
 
            OnGettingValue(key, ref value, out canCache);
 
            if (key != null && canCache)
            {
                if (!Object.Equals(_baseDictionary[key], value))
                {
                    // cache the revised value, after setting its InheritanceContext
                    if (InheritanceContext != null)
                    {
                        AddInheritanceContext(InheritanceContext, value);
                    }
 
                    _baseDictionary[key] = value;
                }
            }
        }
 
        protected virtual void OnGettingValue(object key, ref object value, out bool canCache)
        {
            KeyRecord keyRecord = value as KeyRecord;
 
            // If the value is not a key record then
            // it has already been realized, is not deferred and is a "ready to go" value.
            if (keyRecord == null)
            {
                canCache = true;
                return;   /* Not deferred content */
            }
 
            Debug.Assert(_numDefer > 0, "The stream was closed before all deferred content was loaded.");
 
            // We want to return null if a resource asks for itself. It should return null
            //  <Style x:Key={x:Type Button} BasedOn={StaticResource {x:Type Button}}/> should not find itself
            if (_deferredLocationList.Contains(keyRecord))
            {
                canCache = false;
                value = null;
                return; /* Not defered content */
            }
 
            _deferredLocationList.Add(keyRecord);
 
            try
            {
                if (TraceResourceDictionary.IsEnabled)
                {
                    TraceResourceDictionary.Trace(
                        TraceEventType.Start,
                        TraceResourceDictionary.RealizeDeferContent,
                        this,
                        key,
                        value);
                }
 
                value = CreateObject(keyRecord);
 
            }
            finally
            {
                if (TraceResourceDictionary.IsEnabled)
                {
                    TraceResourceDictionary.Trace(
                        TraceEventType.Stop,
                        TraceResourceDictionary.RealizeDeferContent,
                        this,
                        key,
                        value);
                }
 
            }
 
            _deferredLocationList.Remove(keyRecord);
 
            if (key != null)
            {
                canCache = CanCache(keyRecord, value);
                if (canCache)
                {
                    // Seal styles and templates within App and Theme dictionary
                    SealValue(value);
 
                    _numDefer--;
 
                    if (_numDefer == 0)
                    {
                            CloseReader();
                    }
                }
            }
            else
            {
                canCache = true;
            }
        }
 
        /// <summary>
        ///  Add a byte array that contains deferable content
        /// </summary>
        private void SetDeferrableContent(DeferrableContent deferrableContent)
        {
            Debug.Assert(deferrableContent.Stream != null);
            Debug.Assert(deferrableContent.SchemaContext != null);
            Debug.Assert(deferrableContent.ObjectWriterFactory != null);
            Debug.Assert(deferrableContent.ServiceProvider != null);
            Debug.Assert(deferrableContent.RootObject != null);
 
            Baml2006ReaderSettings settings = new Baml2006ReaderSettings(deferrableContent.SchemaContext.Settings);
            settings.IsBamlFragment = true;
            settings.OwnsStream = true;
            settings.BaseUri = null;    // Base URI can only be set on the root object, not on deferred content.
 
            Baml2006Reader reader = new Baml2006Reader(deferrableContent.Stream,
                deferrableContent.SchemaContext, settings);
            _objectWriterFactory = deferrableContent.ObjectWriterFactory;
            _objectWriterSettings = deferrableContent.ObjectWriterParentSettings;
            _deferredLocationList = new List<KeyRecord>();
            _rootElement = deferrableContent.RootObject;
 
            IList<KeyRecord> keys = reader.ReadKeys();
 
            // If we already have the Source set then we can ignore
            // this deferable content section
            if (_source == null)
            {
                if (_reader == null)
                {
                    _reader = reader;
                    SetKeys(keys, deferrableContent.ServiceProvider);
                }
                else
                {
                    throw new InvalidOperationException(SR.ResourceDictionaryDuplicateDeferredContent);
                }
            }
            else if (keys.Count > 0)
            {
                throw new InvalidOperationException(SR.ResourceDictionaryDeferredContentFailure);
            }
        }
 
        private object GetKeyValue(KeyRecord key, IServiceProvider serviceProvider)
        {
            if (key.KeyString != null)
            {
                return key.KeyString;
            }
            else if (key.KeyType != null)
            {
                return key.KeyType;
            }
            else
            {
                System.Xaml.XamlReader reader = key.KeyNodeList.GetReader();
                object value = EvaluateMarkupExtensionNodeList(reader, serviceProvider);
                return value;
            }
        }
 
        private object EvaluateMarkupExtensionNodeList(System.Xaml.XamlReader reader, IServiceProvider serviceProvider)
        {
            System.Xaml.XamlObjectWriter writer = _objectWriterFactory.GetXamlObjectWriter(null);
 
            System.Xaml.XamlServices.Transform(reader, writer);
 
            object value = writer.Result;
            MarkupExtension me = value as MarkupExtension;
            if (me != null)
            {
                value = me.ProvideValue(serviceProvider);
            }
            return value;
        }
 
        private object GetStaticResourceKeyValue(StaticResource staticResource, IServiceProvider serviceProvider)
        {
            System.Xaml.XamlReader reader = staticResource.ResourceNodeList.GetReader();
            XamlType xamlTypeStaticResourceExtension = reader.SchemaContext.GetXamlType(typeof(StaticResourceExtension));
            XamlMember xamlMemberResourceKey = xamlTypeStaticResourceExtension.GetMember("ResourceKey");
            reader.Read();
            if (reader.NodeType == Xaml.XamlNodeType.StartObject && reader.Type == xamlTypeStaticResourceExtension)
            {
                reader.Read();
                // Skip Members that aren't _PositionalParameters or ResourceKey
                while (reader.NodeType == Xaml.XamlNodeType.StartMember &&
                    (reader.Member != XamlLanguage.PositionalParameters && reader.Member != xamlMemberResourceKey))
                {
                    reader.Skip();
                }
 
                // Process the Member Value of _PositionParameters or ResourceKey
                if (reader.NodeType == Xaml.XamlNodeType.StartMember)
                {
                    object value = null;
                    reader.Read();
                    if (reader.NodeType == Xaml.XamlNodeType.StartObject)
                    {
                        System.Xaml.XamlReader subReader = reader.ReadSubtree();
 
                        value = EvaluateMarkupExtensionNodeList(subReader, serviceProvider);
                    }
                    else if (reader.NodeType == Xaml.XamlNodeType.Value)
                    {
                        value = reader.Value;
                    }
                    return value;
                }
            }
            return null;
        }
 
        private void SetKeys(IList<KeyRecord> keyCollection, IServiceProvider serviceProvider)
        {
            _numDefer = keyCollection.Count;
 
            // Allocate one StaticResourceExtension object to use as a "worker".
            StaticResourceExtension staticResourceWorker = new StaticResourceExtension();
 
            // Use the array Count property to avoid range checking inside the loop
            for (int i = 0; i < keyCollection.Count; i++)
            {
                KeyRecord keyRecord = keyCollection[i];
                if (keyRecord != null)
                {
                    object value = GetKeyValue(keyRecord, serviceProvider);
 
                    // Update the HasImplicitStyles flag
                    UpdateHasImplicitStyles(value);
 
                    // Update the HasImplicitDataTemplates flag
                    UpdateHasImplicitDataTemplates(value);
 
                    if (keyRecord != null && keyRecord.HasStaticResources)
                    {
                        SetOptimizedStaticResources(keyRecord.StaticResources, serviceProvider, staticResourceWorker);
                    }
 
                    _baseDictionary.Add(value, keyRecord);
 
                    if (TraceResourceDictionary.IsEnabled)
                    {
                        TraceResourceDictionary.TraceActivityItem(
                            TraceResourceDictionary.SetKey,
                            this,
                            value);
                    }
 
                }
                else
                {
                    throw new ArgumentException(SR.KeyCollectionHasInvalidKey);
                }
            }
 
            // Notify owners of the HasImplicitStyles flag value
            // but there is not need to fire an invalidation.
            NotifyOwners(new ResourcesChangeInfo(null, this));
        }
 
        /// <summary>
        /// Convert the OptimizedStaticResource and StaticResource items into StaticResourceHolders.
        /// A StaticResourceHolder is derived from StaticResourceExtension and is a MarkupExtension.
        /// The differences is that it contain a DeferredResourceReference as its "PrefetchedValue".
        /// DeferredResourceReferences hold the dictionary and the key of the resource.  It is a
        /// way of looking up the reference now (for later use) but not expanding the entry.
        /// Also the dictionary has a reference back to the Deferrred Reference.  If dictionary entry
        /// is modifed the DeferredResourceReference is told and it will grab the old value.
        /// StaticResourceHolder is a MarkupExtension and thus can be returned as a "Value" in the Node Stream.
        ///
        /// Issue:  If there is a ResourceDictionary inside the deferred entry, the entries inside that
        /// RD will not be evaluated when resolving DeferredResourceReferences for a key in that same entry.
        /// Thus the OptimizedStaticResource will either be erronously "not found" or may even map to some
        /// incorrect value higher in the parse tree.  So... In StaticResourceExtension.ProvideValue()
        /// when we have a DeferredResourceReference we search the Deferred Content for a better
        /// closer value before using the DeferredReference.
        /// See StaticResourceExtension.FindTheResourceDictionary() for more details.
        /// </summary>
 
        // As a memory optimization this method is passed a staticResourceExtension instance to use as
        // a worker when calling TryProvideValueInternal, which saves us having to allocate on every call.
        private void SetOptimizedStaticResources(IList<object> staticResources, IServiceProvider serviceProvider, StaticResourceExtension staticResourceWorker)
        {
            Debug.Assert(staticResources != null && staticResources.Count > 0);
            for (int i = 0; i < staticResources.Count; i++)
            {
                object keyValue = null;
 
                // Process OptimizedStaticResource
                var optimizedStaticResource = staticResources[i] as OptimizedStaticResource;
                if (optimizedStaticResource != null)
                {
                    keyValue = optimizedStaticResource.KeyValue;
                }
                else
                {
                    // Process StaticResource  (it holds the NodeList of the StaticResourceExtension)
                    var staticResource = staticResources[i] as StaticResource;
                    if (staticResource != null)
                    {
                        // find and evaluate the Key value of the SR in the SR's node stream.
                        keyValue = GetStaticResourceKeyValue(staticResource, serviceProvider);
                        Debug.Assert(keyValue != null, "Didn't find the ResourceKey property or x:PositionalParameters directive");
                    }
                    else
                    {
                        Debug.Assert(false, "StaticResources[] entry is not a StaticResource not OptimizedStaticResource");
                        continue;  // other types of entries are not processed.
                    }
                }
 
                // Lookup the Key in the current context.  [And return a Deferred Reference Holding SR to it]
                // The current context is the Key table at the top of the Compiled Dictionary.
                // We will look at keys above us in this dictionary and in the dictionaries in objects above
                // us on the parse stack.  And then look in the App and System Themems.
                // This isn't always good enough.  The Static Resource referenced inside the entry may refer
                // to a entry in a sub-dictionary inside the deferred entry.   There is other code, later
                // when evaluating StaticResourceHolders, that does an search of the part that is missed here.
                staticResourceWorker.ResourceKey = keyValue;
                object obj = staticResourceWorker.TryProvideValueInternal(serviceProvider, true /*allowDeferredReference*/, true /* mustReturnDeferredResourceReference */);
 
                Debug.Assert(obj is DeferredResourceReference);
                staticResources[i] = new StaticResourceHolder(keyValue, obj as DeferredResourceReference);
            }
        }
 
#if false
        // need to call this (and do similar for Template) to cache RDs.
 
        private void SetStaticResources(object[] staticResourceValues, ParserContext context)
        {
            if (staticResourceValues != null && staticResourceValues.Length > 0)
            {
                bool inDeferredSection = context.InDeferredSection;
 
                for (int i=0; i<staticResourceValues.Length; i++)
                {
                    // If this dictionary is a top level deferred section then we lookup the parser stack
                    // and then look in the app and theme dictionaries to resolve the current static resource.
 
                    if (!inDeferredSection)
                    {
                        staticResourceValues[i] = context.BamlReader.FindResourceInParentChain(
                            ((StaticResourceExtension)staticResourceValues[i]).ResourceKey,
                            true /*allowDeferredResourceReference*/,
                            true /*mustReturnDeferredResourceReference*/);
                    }
                    else
                    {
                        // If this dictionary is nested within another deferred section then we try to
                        // resolve the current staticresource against the parser stack and if not
                        // able to resolve then we fallback to the pre-fetched value from the outer
                        // deferred section.
 
                        StaticResourceHolder srHolder = (StaticResourceHolder)staticResourceValues[i];
 
                        object value = context.BamlReader.FindResourceInParserStack(
                            srHolder.ResourceKey,
                            true /*allowDeferredResourceReference*/,
                            true /*mustReturnDeferredResourceReference*/);
 
                        if (value == DependencyProperty.UnsetValue)
                        {
                            // If value wan't found the fallback
                            // to the prefetched value
 
                            value = srHolder.PrefetchedValue;
                        }
 
                        staticResourceValues[i] = value;
                    }
                }
            }
        }
#endif
        private Type GetTypeOfFirstObject(KeyRecord keyRecord)
        {
            Type rootType = _reader.GetTypeOfFirstStartObject(keyRecord);
            return rootType ?? typeof(String);
        }
 
        private object CreateObject(KeyRecord key)
        {
            System.Xaml.XamlReader xamlReader = _reader.ReadObject(key);
            // v3 Markup Compiler will occasionally produce deferred
            // content with keys but no values.  We need to allow returning
            // null in this scenario to match v3 compat and not throw an
            // error.
            if (xamlReader == null)
                return null;
 
            Uri baseUri = (_rootElement is IUriContext) ? ((IUriContext)_rootElement).BaseUri : _baseUri;
            return WpfXamlLoader.LoadDeferredContent(
                    xamlReader, _objectWriterFactory, false /*skipJournaledProperites*/,
                    _rootElement, _objectWriterSettings, baseUri);
        }
 
        // Moved "Lookup()" from 3.5 BamlRecordReader to 4.0 ResourceDictionary
        internal object Lookup(object key, bool allowDeferredResourceReference, bool mustReturnDeferredResourceReference, bool canCacheAsThemeResource)
        {
            if (allowDeferredResourceReference)
            {
                // Attempt to delay load resources from ResourceDictionaries
                bool canCache;
                return FetchResource(key, allowDeferredResourceReference, mustReturnDeferredResourceReference, canCacheAsThemeResource, out canCache);
            }
            else
            {
                if (!mustReturnDeferredResourceReference)
                {
                    return this[key];
                }
                else
                {
                    return new DeferredResourceReferenceHolder(key, this[key]);
                }
            }
        }
 
        #endregion DeferContent
 
        #region HelperMethods
 
        // Add an owner for this dictionary
        internal void AddOwner(DispatcherObject owner)
        {
            if (_inheritanceContext == null)
            {
                // the first owner gets to be the InheritanceContext for
                // all the values in the dictionary that want one.
                DependencyObject inheritanceContext = owner as DependencyObject;
 
                if (inheritanceContext != null)
                {
                    _inheritanceContext = new WeakReference(inheritanceContext);
 
                    // set InheritanceContext for the existing values
                    AddInheritanceContextToValues();
                }
                else
                {
                    // if the first owner is ineligible, use a dummy
                    _inheritanceContext = new WeakReference(DummyInheritanceContext);
 
                    // do not call AddInheritanceContextToValues -
                    // the owner is an Application, and we'll be
                    // calling SealValues soon, which takes care
                    // of InheritanceContext as well
                }
 
            }
 
            FrameworkElement fe = owner as FrameworkElement;
            if (fe != null)
            {
                if (_ownerFEs == null)
                {
                    _ownerFEs = new WeakReferenceList(1);
                }
                else if (_ownerFEs.Contains(fe) && ContainsCycle(this))
                {
                    throw new InvalidOperationException(SR.ResourceDictionaryInvalidMergedDictionary);
                }
 
                // Propagate the HasImplicitStyles flag to the new owner
                if (HasImplicitStyles)
                {
                    fe.ShouldLookupImplicitStyles = true;
                }
 
                _ownerFEs.Add(fe);
            }
            else
            {
                FrameworkContentElement fce = owner as FrameworkContentElement;
                if (fce != null)
                {
                    if (_ownerFCEs == null)
                    {
                        _ownerFCEs = new WeakReferenceList(1);
                    }
                    else if (_ownerFCEs.Contains(fce) && ContainsCycle(this))
                    {
                        throw new InvalidOperationException(SR.ResourceDictionaryInvalidMergedDictionary);
                    }
 
                    // Propagate the HasImplicitStyles flag to the new owner
                    if (HasImplicitStyles)
                    {
                        fce.ShouldLookupImplicitStyles = true;
                    }
 
                    _ownerFCEs.Add(fce);
                }
                else
                {
                    Application app = owner as Application;
                    if (app != null)
                    {
                        if (_ownerApps == null)
                        {
                            _ownerApps = new WeakReferenceList(1);
                        }
                        else if (_ownerApps.Contains(app) && ContainsCycle(this))
                        {
                            throw new InvalidOperationException(SR.ResourceDictionaryInvalidMergedDictionary);
                        }
 
                        // Propagate the HasImplicitStyles flag to the new owner
                        if (HasImplicitStyles)
                        {
                            app.HasImplicitStylesInResources = true;
                        }
 
                        _ownerApps.Add(app);
 
                        // An Application ResourceDictionary can be accessed across threads
                        CanBeAccessedAcrossThreads = true;
 
                        // Seal all the styles and templates in this app dictionary
                        SealValues();
                    }
                }
            }
 
            AddOwnerToAllMergedDictionaries(owner);
 
            // This dictionary will be marked initialized if no one has called BeginInit on it.
            // This is done now because having an owner is like a parenting operation for the dictionary.
            TryInitialize();
        }
 
        // Remove an owner for this dictionary
        internal void RemoveOwner(DispatcherObject owner)
        {
            FrameworkElement fe = owner as FrameworkElement;
            if (fe != null)
            {
                if (_ownerFEs != null)
                {
                    _ownerFEs.Remove(fe);
 
                    if (_ownerFEs.Count == 0)
                    {
                        _ownerFEs = null;
                    }
                }
            }
            else
            {
                FrameworkContentElement fce = owner as FrameworkContentElement;
                if (fce != null)
                {
                    if (_ownerFCEs != null)
                    {
                        _ownerFCEs.Remove(fce);
 
                        if (_ownerFCEs.Count == 0)
                        {
                            _ownerFCEs = null;
                        }
                    }
                }
                else
                {
                    Application app = owner as Application;
                    if (app != null)
                    {
                        if (_ownerApps != null)
                        {
                            _ownerApps.Remove(app);
 
                            if (_ownerApps.Count == 0)
                            {
                                _ownerApps = null;
                            }
                        }
                    }
                }
            }
 
            if (owner == InheritanceContext)
            {
                RemoveInheritanceContextFromValues();
                _inheritanceContext = null;
            }
 
            RemoveOwnerFromAllMergedDictionaries(owner);
        }
 
        // Check if the given is an owner to this dictionary
        internal bool ContainsOwner(DispatcherObject owner)
        {
            FrameworkElement fe = owner as FrameworkElement;
            if (fe != null)
            {
                return (_ownerFEs != null && _ownerFEs.Contains(fe));
            }
            else
            {
                FrameworkContentElement fce = owner as FrameworkContentElement;
                if (fce != null)
                {
                    return (_ownerFCEs != null && _ownerFCEs.Contains(fce));
                }
                else
                {
                    Application app = owner as Application;
                    if (app != null)
                    {
                        return (_ownerApps != null && _ownerApps.Contains(app));
                    }
                }
            }
 
            return false;
        }
 
        // Helper method that tries to set IsInitialized to true if BeginInit hasn't been called before this.
        // This method is called on AddOwner
        private void TryInitialize()
        {
            if (!IsInitializePending &&
                !IsInitialized)
            {
                IsInitialized = true;
            }
        }
 
        // Call FrameworkElement.InvalidateTree with the right data
        private void NotifyOwners(ResourcesChangeInfo info)
        {
            bool shouldInvalidate   = IsInitialized;
            bool hasImplicitStyles  = info.IsResourceAddOperation && HasImplicitStyles;
 
            if (shouldInvalidate && InvalidatesImplicitDataTemplateResources)
            {
                info.SetIsImplicitDataTemplateChange();
            }
 
            if (shouldInvalidate || hasImplicitStyles)
            {
                // Invalidate all FE owners
                if (_ownerFEs != null)
                {
                    foreach (Object o in _ownerFEs)
                    {
                        FrameworkElement fe = o as FrameworkElement;
                        if (fe != null)
                        {
                            // Set the HasImplicitStyles flag on the owner
                            if (hasImplicitStyles)
                                fe.ShouldLookupImplicitStyles = true;
 
                            // If this dictionary has been initialized fire an invalidation
                            // to let the tree know of this change.
                            if (shouldInvalidate)
                                TreeWalkHelper.InvalidateOnResourcesChange(fe, null, info);
                        }
                    }
                }
 
                // Invalidate all FCE owners
                if (_ownerFCEs != null)
                {
                    foreach (Object o in _ownerFCEs)
                    {
                        FrameworkContentElement fce = o as FrameworkContentElement;
                        if (fce != null)
                        {
                            // Set the HasImplicitStyles flag on the owner
                            if (hasImplicitStyles)
                                fce.ShouldLookupImplicitStyles = true;
 
                            // If this dictionary has been initialized fire an invalidation
                            // to let the tree know of this change.
                            if (shouldInvalidate)
                                TreeWalkHelper.InvalidateOnResourcesChange(null, fce, info);
                        }
                    }
                }
 
                // Invalidate all App owners
                if (_ownerApps != null)
                {
                    foreach (Object o in _ownerApps)
                    {
                        Application app = o as Application;
                        if (app != null)
                        {
                            // Set the HasImplicitStyles flag on the owner
                            if (hasImplicitStyles)
                                app.HasImplicitStylesInResources = true;
 
                            // If this dictionary has been initialized fire an invalidation
                            // to let the tree know of this change.
                            if (shouldInvalidate)
                                app.InvalidateResourceReferences(info);
                        }
                    }
                }
            }
        }
 
        /// <summary>
        /// Fetches the resource corresponding to the given key from this dictionary.
        /// Returns a DeferredResourceReference if the object has not been inflated yet.
        /// </summary>
        internal object FetchResource(
            object      resourceKey,
            bool        allowDeferredResourceReference,
            bool        mustReturnDeferredResourceReference,
            out bool    canCache)
        {
            return FetchResource(
                resourceKey,
                allowDeferredResourceReference,
                mustReturnDeferredResourceReference,
                true /*canCacheAsThemeResource*/,
                out canCache);
        }
 
        /// <summary>
        /// Fetches the resource corresponding to the given key from this dictionary.
        /// Returns a DeferredResourceReference if the object has not been inflated yet.
        /// </summary>
        private object FetchResource(
            object      resourceKey,
            bool        allowDeferredResourceReference,
            bool        mustReturnDeferredResourceReference,
            bool        canCacheAsThemeResource,
            out bool    canCache)
        {
            Debug.Assert(resourceKey != null, "ResourceKey cannot be null");
 
            if (allowDeferredResourceReference)
            {
                if (ContainsBamlObjectFactory(resourceKey) ||
                    (mustReturnDeferredResourceReference && Contains(resourceKey)))
                {
                    canCache = false;
 
                    DeferredResourceReference deferredResourceReference;
                    if (!IsThemeDictionary)
                    {
                        if (FrameworkAppContextSwitches.DisableDynamicResourceOptimization)
                        {
                            if (_ownerApps is not null)
                            {
                                deferredResourceReference = new DeferredAppResourceReference(this, resourceKey);
                            }
                            else
                            {
                                deferredResourceReference = new DeferredResourceReference(this, resourceKey);
                            }
 
                            // Cache the deferredResourceReference so that it can be validated
                            // in case of a dictionary change prior to its inflation
                            if (_weakDeferredResourceReferences is null)
                            {
                                _weakDeferredResourceReferences = new WeakReferenceList();
                            }
 
                            _weakDeferredResourceReferences.Add(deferredResourceReference, true /*SkipFind*/);
                        }
                        else
                        {
                            // Cache the deferredResourceReference so that it can be validated
                            // in case of a dictionary change prior to its inflation
                            _deferredResourceReferencesList ??= new DeferredResourceReferenceList();
 
                            if (_deferredResourceReferencesList.Get(resourceKey) is { } existingDeferredResourceReference
                                && existingDeferredResourceReference.Dictionary == this)
                            {
                                deferredResourceReference = existingDeferredResourceReference;
                            }
                            else
                            {
                                deferredResourceReference = _ownerApps is not null ? new DeferredAppResourceReference(this, resourceKey) : new DeferredResourceReference(this, resourceKey);
 
                                _deferredResourceReferencesList.AddOrSet(deferredResourceReference);
                            }
                        }
                    }
                    else
                    {
                        deferredResourceReference = new DeferredThemeResourceReference(this, resourceKey, canCacheAsThemeResource);
                    }
 
                    ResourceDictionaryDiagnostics.RecordLookupResult(resourceKey, this);
 
                    return deferredResourceReference;
                }
            }
 
            return GetValue(resourceKey, out canCache);
        }
 
        /// <summary>
        /// Validate the deferredResourceReference with the given key. Key could be null meaning
        /// some catastrophic operation occurred so simply validate all DeferredResourceReferences
        /// </summary>
        private void ValidateDeferredResourceReferences(object resourceKey)
        {
            if (FrameworkAppContextSwitches.DisableDynamicResourceOptimization)
            {
                if (_weakDeferredResourceReferences != null)
                {
                    foreach (Object o in _weakDeferredResourceReferences)
                    {
                        DeferredResourceReference deferredResourceReference = o as DeferredResourceReference;
                        if (deferredResourceReference != null && (resourceKey == null || Object.Equals(resourceKey, deferredResourceReference.Key)))
                        {
                            // This will inflate the deferred reference, causing it
                            // to be removed from the list.  The list may also be
                            // purged of dead references.
                            deferredResourceReference.GetValue(BaseValueSourceInternal.Unknown);
                        }
                    }
                }
            }
            else
            {
                if (_deferredResourceReferencesList is null)
                {
                    return;
                }
 
                if (resourceKey is null)
                {
                    foreach (DeferredResourceReference deferredResourceReference in _deferredResourceReferencesList)
                    {
                        Inflate(deferredResourceReference);
                    }
                }
                else
                {
                    DeferredResourceReference deferredResourceReference = _deferredResourceReferencesList.Get(resourceKey);
 
                    Inflate(deferredResourceReference);
                }
 
                return;
 
                void Inflate(DeferredResourceReference deferredResourceReference)
                {
                    if (deferredResourceReference is not null)
                    {
                        // This will inflate the deferred reference, causing it
                        // to be removed from the list.  The list may also be
                        // purged of dead references.
                        deferredResourceReference.GetValue(BaseValueSourceInternal.Unknown);
                    }
                }
            }
        }
 
        /// <summary>
        /// Called when the MergedDictionaries collection changes
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnMergedDictionariesChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            List<ResourceDictionary> oldDictionaries = null;
            List<ResourceDictionary> newDictionaries = null;
            ResourceDictionary mergedDictionary;
            ResourcesChangeInfo info;
 
            if (e.Action != NotifyCollectionChangedAction.Reset)
            {
                Invariant.Assert(
                    (e.NewItems != null && e.NewItems.Count > 0) ||
                    (e.OldItems != null && e.OldItems.Count > 0),
                    "The NotifyCollectionChanged event fired when no dictionaries were added or removed");
 
 
                // If one or more resource dictionaries were removed we
                // need to remove the owners they were given by their
                // parent ResourceDictionary.
 
                if (e.Action == NotifyCollectionChangedAction.Remove
                    || e.Action == NotifyCollectionChangedAction.Replace)
                {
                    oldDictionaries = new List<ResourceDictionary>(e.OldItems.Count);
 
                    for (int i = 0; i < e.OldItems.Count; i++)
                    {
                        mergedDictionary = (ResourceDictionary)e.OldItems[i];
                        oldDictionaries.Add(mergedDictionary);
 
                        RemoveParentOwners(mergedDictionary);
                    }
                }
 
                // If one or more resource dictionaries were added to the merged
                // dictionaries collection we need to send down the parent
                // ResourceDictionary's owners.
 
                if (e.Action == NotifyCollectionChangedAction.Add
                    || e.Action == NotifyCollectionChangedAction.Replace)
                {
                    newDictionaries = new List<ResourceDictionary>(e.NewItems.Count);
 
                    for (int i = 0; i < e.NewItems.Count; i++)
                    {
                        mergedDictionary = (ResourceDictionary)e.NewItems[i];
                        newDictionaries.Add(mergedDictionary);
 
                        // If the merged dictionary HasImplicitStyle mark the outer dictionary the same.
                        if (!HasImplicitStyles && mergedDictionary.HasImplicitStyles)
                        {
                            HasImplicitStyles = true;
                        }
 
                        // If the merged dictionary HasImplicitDataTemplates mark the outer dictionary the same.
                        if (!HasImplicitDataTemplates && mergedDictionary.HasImplicitDataTemplates)
                        {
                            HasImplicitDataTemplates = true;
                        }
 
                        // If the parent dictionary is a theme dictionary mark the merged dictionary the same.
                        if (IsThemeDictionary)
                        {
                            mergedDictionary.IsThemeDictionary = true;
                        }
 
                        PropagateParentOwners(mergedDictionary);
                    }
                }
 
                info = new ResourcesChangeInfo(oldDictionaries, newDictionaries, false, false, null);
            }
            else
            {
                // Case when MergedDictionary collection is cleared
                info = ResourcesChangeInfo.CatastrophicDictionaryChangeInfo;
            }
 
            // Notify the owners of the change and fire
            // invalidation if already initialized
 
            NotifyOwners(info);
        }
 
        /// <summary>
        /// Adds the given owner to all merged dictionaries of this ResourceDictionary
        /// </summary>
        /// <param name="owner"></param>
        private void AddOwnerToAllMergedDictionaries(DispatcherObject owner)
        {
            if (_mergedDictionaries != null)
            {
                for (int i = 0; i < _mergedDictionaries.Count; i++)
                {
                    _mergedDictionaries[i].AddOwner(owner);
                }
            }
        }
 
        /// <summary>
        ///
        /// </summary>
        /// <param name="owner"></param>
        private void RemoveOwnerFromAllMergedDictionaries(DispatcherObject owner)
        {
            if (_mergedDictionaries != null)
            {
                for (int i = 0; i < _mergedDictionaries.Count; i++)
                {
                    _mergedDictionaries[i].RemoveOwner(owner);
                }
            }
        }
 
        /// <summary>
        /// This sends down the owners of this ResourceDictionary into the given
        /// merged dictionary.  We do this because whenever a merged dictionary
        /// changes it should invalidate all owners of its parent ResourceDictionary.
        ///
        /// Note that AddOwners throw if the merged dictionary already has one of the
        /// parent's owners.  This implies that either we're putting a dictionary
        /// into its own MergedDictionaries collection or we're putting the same
        /// dictionary into the collection twice, neither of which are legal.
        /// </summary>
        /// <param name="mergedDictionary"></param>
        private void PropagateParentOwners(ResourceDictionary mergedDictionary)
        {
            if (_ownerFEs != null)
            {
                Invariant.Assert(_ownerFEs.Count > 0);
 
                if (mergedDictionary._ownerFEs == null)
                {
                    mergedDictionary._ownerFEs = new WeakReferenceList(_ownerFEs.Count);
                }
 
                foreach (object o in _ownerFEs)
                {
                    FrameworkElement fe = o as FrameworkElement;
                    if (fe != null)
                        mergedDictionary.AddOwner(fe);
                }
            }
 
            if (_ownerFCEs != null)
            {
                Invariant.Assert(_ownerFCEs.Count > 0);
 
                if (mergedDictionary._ownerFCEs == null)
                {
                    mergedDictionary._ownerFCEs = new WeakReferenceList(_ownerFCEs.Count);
                }
 
                foreach (object o in _ownerFCEs)
                {
                    FrameworkContentElement fce = o as FrameworkContentElement;
                    if (fce != null)
                        mergedDictionary.AddOwner(fce);
                }
            }
 
            if (_ownerApps != null)
            {
                Invariant.Assert(_ownerApps.Count > 0);
 
                if (mergedDictionary._ownerApps == null)
                {
                    mergedDictionary._ownerApps = new WeakReferenceList(_ownerApps.Count);
                }
 
                foreach (object o in _ownerApps)
                {
                    Application app = o as Application;
                    if (app != null)
                        mergedDictionary.AddOwner(app);
                }
            }
        }
 
 
        /// <summary>
        /// Removes the owners of this ResourceDictionary from the given
        /// merged dictionary.  The merged dictionary will be left with
        /// whatever owners it had before being merged.
        /// </summary>
        /// <param name="mergedDictionary"></param>
        internal void RemoveParentOwners(ResourceDictionary mergedDictionary)
        {
            if (_ownerFEs != null)
            {
                foreach (Object o in _ownerFEs)
                {
                    FrameworkElement fe = o as FrameworkElement;
                    mergedDictionary.RemoveOwner(fe);
 
                }
            }
 
            if (_ownerFCEs != null)
            {
                Invariant.Assert(_ownerFCEs.Count > 0);
 
                foreach (Object o in _ownerFCEs)
                {
                    FrameworkContentElement fec = o as FrameworkContentElement;
                    mergedDictionary.RemoveOwner(fec);
 
                }
            }
 
            if (_ownerApps != null)
            {
                Invariant.Assert(_ownerApps.Count > 0);
 
                foreach (Object o in _ownerApps)
                {
                    Application app = o as Application;
                    mergedDictionary.RemoveOwner(app);
 
                }
            }
        }
 
        private bool ContainsCycle(ResourceDictionary origin)
        {
            for (int i=0; i<MergedDictionaries.Count; i++)
            {
                ResourceDictionary mergedDictionary = MergedDictionaries[i];
                if (mergedDictionary == origin || mergedDictionary.ContainsCycle(origin))
                {
                    return true;
                }
            }
 
            return false;
        }
 
        // three properties used by ResourceDictionaryDiagnostics
 
        internal WeakReferenceList FrameworkElementOwners
        {
            get { return _ownerFEs; }
        }
 
        internal WeakReferenceList FrameworkContentElementOwners
        {
            get { return _ownerFCEs; }
        }
 
        internal WeakReferenceList ApplicationOwners
        {
            get { return _ownerApps; }
        }
 
        #endregion HelperMethods
 
        #region Properties
 
        internal WeakReferenceList WeakDeferredResourceReferences
        {
            get { return _weakDeferredResourceReferences; }
        }
 
        internal DeferredResourceReferenceList DeferredResourceReferencesList
        {
            get { return _deferredResourceReferencesList; }
        }
 
        #endregion Properties
 
        #region Enumeration
 
        /// <summary>
        ///     Iterates the dictionary's entries, handling deferred content.
        /// </summary>
        private class ResourceDictionaryEnumerator : IDictionaryEnumerator
        {
            internal ResourceDictionaryEnumerator(ResourceDictionary owner)
            {
                _owner = owner;
                _keysEnumerator = _owner.Keys.GetEnumerator();
            }
 
            #region IEnumerator
 
            object IEnumerator.Current
            {
                get
                {
                    return ((IDictionaryEnumerator)this).Entry;
                }
            }
 
            bool IEnumerator.MoveNext()
            {
                return _keysEnumerator.MoveNext();
            }
 
            void IEnumerator.Reset()
            {
                _keysEnumerator.Reset();
            }
 
            #endregion
 
            #region IDictionaryEnumerator
 
            DictionaryEntry IDictionaryEnumerator.Entry
            {
                get
                {
                    object key = _keysEnumerator.Current;
                    object value = _owner[key];
                    return new DictionaryEntry(key, value);
                }
            }
 
            object IDictionaryEnumerator.Key
            {
                get
                {
                    return _keysEnumerator.Current;
                }
            }
 
            object IDictionaryEnumerator.Value
            {
                get
                {
                    return _owner[_keysEnumerator.Current];
                }
            }
 
            #endregion
 
            #region Data
 
            private ResourceDictionary _owner;
            private IEnumerator _keysEnumerator;
 
            #endregion
        }
 
        /// <summary>
        ///     Iterator for the dictionary's Values collection, handling deferred content.
        /// </summary>
        private class ResourceValuesEnumerator : IEnumerator
        {
            internal ResourceValuesEnumerator(ResourceDictionary owner)
            {
                _owner = owner;
                _keysEnumerator = _owner.Keys.GetEnumerator();
            }
 
            #region IEnumerator
 
            object IEnumerator.Current
            {
                get
                {
                    return _owner[_keysEnumerator.Current];
                }
            }
 
            bool IEnumerator.MoveNext()
            {
                return _keysEnumerator.MoveNext();
            }
 
            void IEnumerator.Reset()
            {
                _keysEnumerator.Reset();
            }
 
            #endregion
 
            #region Data
 
            private ResourceDictionary _owner;
            private IEnumerator _keysEnumerator;
 
            #endregion
        }
 
        /// <summary>
        ///     Represents the dictionary's Values collection, handling deferred content.
        /// </summary>
        private class ResourceValuesCollection : ICollection
        {
            internal ResourceValuesCollection(ResourceDictionary owner)
            {
                _owner = owner;
            }
 
            #region ICollection
 
            int ICollection.Count
            {
                get
                {
                    return _owner.Count;
                }
            }
 
            bool ICollection.IsSynchronized
            {
                get
                {
                    return false;
                }
            }
 
            object ICollection.SyncRoot
            {
                get
                {
                    return this;
                }
            }
 
            void ICollection.CopyTo(Array array, int index)
            {
                foreach (object key in _owner.Keys)
                {
                    array.SetValue(_owner[key], index++);
                }
            }
 
            IEnumerator IEnumerable.GetEnumerator()
            {
                return new ResourceValuesEnumerator(_owner);
            }
 
            #endregion
 
            #region Data
 
            private ResourceDictionary _owner;
 
            #endregion
        }
 
        #endregion Enumeration
 
        #region PrivateMethods
 
        //
        //  This method
        //  1. Seals all the freezables/styles/templates that belong to this App/Theme/Style/Template ResourceDictionary
        //
        private void SealValues()
        {
            Debug.Assert(IsThemeDictionary || _ownerApps != null || IsReadOnly, "This must be an App/Theme/Style/Template ResourceDictionary");
 
            // sealing can cause DeferredResourceReferences to be replaced by the
            // inflated values.  This changes the Values collection,
            // so we can't iterate it directly.  Instead, iterate over a copy.
            int count = _baseDictionary.Count;
            if (count > 0)
            {
                object[] values = new object[count];
                _baseDictionary.Values.CopyTo(values, 0);
 
                foreach (object value in values)
                {
                    SealValue(value);
                }
            }
        }
 
        //
        //  This method
        //  1. Sets the InheritanceContext of the value to the dictionary's principal owner
        //  2. Seals the freezable/style/template that is to be placed in an App/Theme/Style/Template ResourceDictionary
        //
        private void SealValue(object value)
        {
            DependencyObject inheritanceContext = InheritanceContext;
            if (inheritanceContext != null)
            {
                AddInheritanceContext(inheritanceContext, value);
            }
 
            if (IsThemeDictionary || _ownerApps != null || IsReadOnly)
            {
                // If the value is a ISealable then seal it
                StyleHelper.SealIfSealable(value);
            }
        }
 
        // add inheritance context to a value
        private void AddInheritanceContext(DependencyObject inheritanceContext, object value)
        {
            // The VisualBrush.Visual property is the "friendliest", i.e. the
            // most likely to be accepted by the resource as FEs need to accept
            // being rooted by a VisualBrush.
            //
            // NOTE:  Freezable.Debug_VerifyContextIsValid() contains a special
            //        case to allow this with the VisualBrush.Visual property.
            //        Changes made here will require updates in Freezable.cs
            if (inheritanceContext.ProvideSelfAsInheritanceContext(value, VisualBrush.VisualProperty))
            {
                // if the assignment was successful, seal the value's InheritanceContext.
                // This makes sure the resource always gets inheritance-related information
                // from its point of definition, not from its point of use.
                DependencyObject doValue = value as DependencyObject;
                if (doValue != null)
                {
                    doValue.IsInheritanceContextSealed = true;
                }
            }
        }
 
        // add inheritance context to all values that came from this dictionary
        private void AddInheritanceContextToValues()
        {
            DependencyObject inheritanceContext = InheritanceContext;
 
            // setting InheritanceContext can cause values to be replaced.
            // This changes the Values collection, so we can't iterate it directly.
            // Instead, iterate over a copy.
            int count = _baseDictionary.Count;
            if (count > 0)
            {
                object[] values = new object[count];
                _baseDictionary.Values.CopyTo(values, 0);
 
                foreach (object value in values)
                {
                    AddInheritanceContext(inheritanceContext, value);
                }
            }
        }
 
        // remove inheritance context from a value, if it came from this dictionary
        private void RemoveInheritanceContext(object value)
        {
            DependencyObject doValue = value as DependencyObject;
            DependencyObject inheritanceContext = InheritanceContext;
 
            if (doValue != null && inheritanceContext != null &&
                doValue.IsInheritanceContextSealed &&
                doValue.InheritanceContext == inheritanceContext)
            {
                doValue.IsInheritanceContextSealed = false;
                inheritanceContext.RemoveSelfAsInheritanceContext(doValue, VisualBrush.VisualProperty);
            }
        }
 
        // remove inheritance context from all values that came from this dictionary
        private void RemoveInheritanceContextFromValues()
        {
            foreach (object value in _baseDictionary.Values)
            {
                RemoveInheritanceContext(value);
            }
        }
 
 
        // Sets the HasImplicitStyles flag if the given key is of type Type.
        private void UpdateHasImplicitStyles(object key)
        {
            // Update the HasImplicitStyles flag
            if (!HasImplicitStyles)
            {
                HasImplicitStyles = ((key as Type) != null);
            }
        }
 
        // Sets the HasImplicitDataTemplates flag if the given key is of type DataTemplateKey.
        private void UpdateHasImplicitDataTemplates(object key)
        {
            // Update the HasImplicitDataTemplates flag
            if (!HasImplicitDataTemplates)
            {
                HasImplicitDataTemplates = (key is DataTemplateKey);
            }
        }
 
        private DependencyObject InheritanceContext
        {
            get
            {
                return (_inheritanceContext != null)
                    ? (DependencyObject)_inheritanceContext.Target
                    : null;
            }
        }
 
        private bool IsInitialized
        {
            get { return ReadPrivateFlag(PrivateFlags.IsInitialized); }
            set { WritePrivateFlag(PrivateFlags.IsInitialized, value); }
        }
 
        private bool IsInitializePending
        {
            get { return ReadPrivateFlag(PrivateFlags.IsInitializePending); }
            set { WritePrivateFlag(PrivateFlags.IsInitializePending, value); }
        }
 
        private bool IsThemeDictionary
        {
            get { return ReadPrivateFlag(PrivateFlags.IsThemeDictionary); }
            set
            {
                if (IsThemeDictionary != value)
                {
                    WritePrivateFlag(PrivateFlags.IsThemeDictionary, value);
                    if (value)
                    {
                        SealValues();
                    }
                    if (_mergedDictionaries != null)
                    {
                        for (int i=0; i<_mergedDictionaries.Count; i++)
                        {
                            _mergedDictionaries[i].IsThemeDictionary = value;
                        }
                    }
                }
            }
        }
 
        internal bool HasImplicitStyles
        {
            get { return ReadPrivateFlag(PrivateFlags.HasImplicitStyles); }
            set { WritePrivateFlag(PrivateFlags.HasImplicitStyles, value); }
        }
 
        internal bool HasImplicitDataTemplates
        {
            get { return ReadPrivateFlag(PrivateFlags.HasImplicitDataTemplates); }
            set { WritePrivateFlag(PrivateFlags.HasImplicitDataTemplates, value); }
        }
 
        internal bool CanBeAccessedAcrossThreads
        {
            get { return ReadPrivateFlag(PrivateFlags.CanBeAccessedAcrossThreads); }
            set { WritePrivateFlag(PrivateFlags.CanBeAccessedAcrossThreads, value); }
        }
 
        private void WritePrivateFlag(PrivateFlags bit, bool value)
        {
            if (value)
            {
                _flags |= bit;
            }
            else
            {
                _flags &= ~bit;
            }
        }
 
        private bool ReadPrivateFlag(PrivateFlags bit)
        {
            return (_flags & bit) != 0;
        }
 
        private void CloseReader()
        {
            _reader.Close();
            _reader = null;
        }
 
        private void CopyDeferredContentFrom(ResourceDictionary loadedRD)
        {
            _buffer = loadedRD._buffer;
            _bamlStream = loadedRD._bamlStream;
            _startPosition = loadedRD._startPosition;
            _contentSize = loadedRD._contentSize;
            _objectWriterFactory = loadedRD._objectWriterFactory;
            _objectWriterSettings = loadedRD._objectWriterSettings;
            _rootElement = loadedRD._rootElement;
            _reader = loadedRD._reader;
            _numDefer = loadedRD._numDefer;
            _deferredLocationList = loadedRD._deferredLocationList;
            IsUnsafe = loadedRD.IsUnsafe;
        }
 
        private void  MoveDeferredResourceReferencesFrom(ResourceDictionary loadedRD)
        {
            if (FrameworkAppContextSwitches.DisableDynamicResourceOptimization)
            {
                // copy the list
                _weakDeferredResourceReferences = loadedRD._weakDeferredResourceReferences;
 
                // redirect each entry toward its new owner
                if (_weakDeferredResourceReferences != null)
                {
                    foreach (DeferredResourceReference drr in _weakDeferredResourceReferences)
                    {
                        drr.Dictionary = this;
                    }
                }
            }
            else
            {
                // copy the list
                _deferredResourceReferencesList = loadedRD._deferredResourceReferencesList;
 
                // redirect each entry toward its new owner
                if (_deferredResourceReferencesList != null)
                {
                    _deferredResourceReferencesList.ChangeDictionary(this);
                }
            }
        }
 
        #endregion PrivateMethods
 
        #region PrivateDataStructures
 
        private enum PrivateFlags : byte
        {
            IsInitialized               = 0x01,
            IsInitializePending         = 0x02,
            IsReadOnly                  = 0x04,
            IsThemeDictionary           = 0x08,
            HasImplicitStyles           = 0x10,
            CanBeAccessedAcrossThreads  = 0x20,
            InvalidatesImplicitDataTemplateResources = 0x40,
            HasImplicitDataTemplates    = 0x80,
        }
 
        /// <summary>
        /// This wrapper class exists so SourceUriTypeConverterMarkupExtension can pass
        /// a more complete Uri to help resolve to the correct assembly, while also passing
        /// the original Uri so that ResourceDictionary.Source still returns the original value.
        /// </summary>
        internal class ResourceDictionarySourceUriWrapper : Uri
        {
            public ResourceDictionarySourceUriWrapper(Uri originalUri, Uri versionedUri) : base(originalUri.OriginalString, UriKind.RelativeOrAbsolute)
            {
                OriginalUri = originalUri;
                VersionedUri = versionedUri;
            }
 
            internal Uri OriginalUri
            {
                get;
                set;
            }
 
            internal Uri VersionedUri
            {
                get;
                set;
            }
        }
 
        #endregion PrivateDataStructures
 
        // flag set by ThemeDictionaryExtension
        // to know that classic/generic Uri's should be used as fallbacks
        // when themed dictionary is not found
        internal bool IsSourcedFromThemeDictionary = false;
        private FallbackState _fallbackState = FallbackState.Classic;
 
        private enum FallbackState
        {
            Classic,
            Generic,
            None
        }
 
        #region Data
 
        private Hashtable                                 _baseDictionary = null;
        private WeakReferenceList                         _ownerFEs = null;
        private WeakReferenceList                         _ownerFCEs = null;
        private WeakReferenceList                         _ownerApps = null;
        private WeakReferenceList                         _weakDeferredResourceReferences = null;
        private DeferredResourceReferenceList             _deferredResourceReferencesList = null;
        private ObservableCollection<ResourceDictionary>  _mergedDictionaries = null;
        private Uri                                       _source = null;
        private Uri                                       _baseUri = null;
        private PrivateFlags                              _flags = 0;
        private List<KeyRecord>                           _deferredLocationList = null;
 
        // Buffer that contains deferable content.  This may be null if a stream was passed
        // instead of a buffer.  If a buffer was passed, then a memory stream is made on the buffer
        private byte[]          _buffer;
 
        // Persistent Stream that contains values.
        private Stream          _bamlStream;
 
        // Start position in the stream where the first value record is located.  All offsets for
        // the keys are relative to this position.
        private Int64           _startPosition;
 
        // Size of the delay loaded content, which only includes the value section and not the keys.
        private Int32           _contentSize;
 
        // The root element at the time the deferred content information was given to the dictionary.
        private object          _rootElement;
 
        // The number of keys that correspond to deferred content. When this reaches 0,
        // the stream can be closed.
        private int             _numDefer;
 
        // The object that becomes the InheritanceContext of all eligible
        // values in the dictionary - typically the principal owner of the dictionary.
        // We store a weak reference so that the dictionary does not leak the owner.
        private WeakReference   _inheritanceContext;
 
        // a dummy DO, used as the InheritanceContext when the dictionary's owner is
        // not itself a DO
        private static readonly DependencyObject DummyInheritanceContext = new DependencyObject();
 
        XamlObjectIds _contextXamlObjectIds  = new XamlObjectIds();
 
        private IXamlObjectWriterFactory _objectWriterFactory;
        private XamlObjectWriterSettings _objectWriterSettings;
 
        private Baml2006Reader _reader;
 
        #endregion Data
    }
}