File: System\Windows\Markup\BamlRecordReader.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.
 
/***************************************************************************\
*
*
* Purpose:  Main class to handle reading a Baml file
*
\***************************************************************************/
 
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Collections;
using System.ComponentModel;
using System.Reflection;
using System.Globalization;
using MS.Utility;
using MS.Internal;
using MS.Internal.Utility;
using System.Windows.Navigation;
 
// Disabling 1634 and 1691:
// In order to avoid generating warnings about unknown message numbers and
// unknown pragmas when compiling C# source code with the C# compiler,
// you need to disable warnings 1634 and 1691. (Presharp Documentation)
#pragma warning disable 1634, 1691
 
namespace System.Windows.Markup
{
    // Unlike the tokenizer and the writer, the reader knows the difference between CLR
    // object and DependencyObjects.  This is done because DependencyObjects support a
    // superset of CLR functionality, such as the ability to quickly set a property
    // using DependencyObject.SetValue(DependencyProperty, object)
    internal enum ReaderFlags : ushort
    {
        // Context types
        Unknown                   = 0x0000,
 
        DependencyObject          = 0x1000,
        ClrObject                 = 0x2000,
 
        PropertyComplexClr        = 0x3000,
        PropertyComplexDP         = 0x4000,
 
        PropertyArray             = 0x5000,
        PropertyIList             = 0x6000,
        PropertyIDictionary       = 0x7000,
        PropertyIAddChild         = 0x8000,
 
        RealizeDeferContent       = 0x9000,
 
        ConstructorParams         = 0xA000,
 
        ContextTypeMask           = 0xF000,
 
        StyleObject               = 0x0100,
        FrameworkTemplateObject   = 0x0200,
        TableTemplateObject       = 0x0400,
        SingletonConstructorParam = 0x0800,
 
        // Element flags
        NeedToAddToTree           = 0x0001,    // Need to add to element tree, but haven't yet
        AddedToTree               = 0x0002,    // Has already been added to element tree, so don't do it again
        InjectedElement           = 0x0004,    // Context was an injected element, so skip over it
        CollectionHolder          = 0x0008,
        IDictionary               = 0x0010,
        IList                     = 0x0020,
        ArrayExt                  = 0x0040,
        IAddChild                 = 0x0080,
    }
 
    /// <summary>
    /// reads BAML from a Stream
    /// This is an internal class
    /// </summary>
    internal class BamlRecordReader
    {
#region Constructor
        /// <summary>
        /// Eventually should need xamltypemapper when finish compiler integration
        /// and namespaceMaps are written to Baml.
        /// </summary>summary>
        internal BamlRecordReader(
            Stream        bamlStream,
            ParserContext parserContext)
            : this(bamlStream,parserContext,true)
        {
            XamlParseMode = XamlParseMode.Synchronous;
        }
 
        internal BamlRecordReader(
            Stream           bamlStream,
            ParserContext    parserContext,
            object           root)
        {
            Debug.Assert(null != bamlStream);
            Debug.Assert(null != parserContext && null != parserContext.XamlTypeMapper);
 
            ParserContext = parserContext;
            _rootElement = root;
            _bamlAsForest = (root != null);
            if (_bamlAsForest)
            {
                ParserContext.RootElement = _rootElement;
            }
            _rootList = new ArrayList(1);
            BamlStream = bamlStream;
        }
 
        /// <summary>
        /// BamlRecordReader constructor
        /// </summary>
        /// <param name="bamlStream">The input BAML stream</param>
        /// <param name="parserContext">The parser context</param>
        /// <param name="loadMapper">Ensure parser context has same XamlTypeMapper and
        ///                            map table as this reader</param>
        internal BamlRecordReader(
            Stream           bamlStream,
            ParserContext    parserContext,
            bool             loadMapper)
        {
            Debug.Assert(null != parserContext && null != parserContext.XamlTypeMapper);
 
            ParserContext = parserContext;
            _rootList = new ArrayList(1);
            BamlStream = bamlStream;
 
            if (loadMapper)
            {
                ParserContext.XamlTypeMapper = XamlTypeMapper;
            }
        }
 
        /// <summary>
        /// Default internal constructor
        /// </summary>
        protected internal BamlRecordReader()
        {
        }
 
#endregion Constructor
 
#region Methods
 
        /// <summary>
        /// Set up the XamlTypeMapper and baml map table prior to starting to read.
        /// </summary>
        internal void Initialize()
        {
            MapTable.Initialize();
            XamlTypeMapper.Initialize();
            ParserContext.Initialize();
        }
 
        /// <summary>
        /// Array of root objects contained in the baml stream.  This is added to
        /// as the baml is loaded.
        /// </summary>
        internal ArrayList RootList
        {
            get { return _rootList; }
            set { _rootList = value; }
        }
 
 
        /// <summary>
        /// True if tree is to be built strictly (well, more or less strictly)
        /// top down.
        /// </summary>
        internal bool BuildTopDown
        {
            get { return _buildTopDown; }
            set { _buildTopDown = value; }
        }
 
        internal int BytesAvailible
        {
            get
            {
                Stream stream = BinaryReader.BaseStream;
                return (int)(stream.Length - stream.Position);
            }
        }
 
        /// <summary>
        /// Read a BamlRecord from the underlying binary stream and return it.
        /// If we're at the end of the stream, return null.
        /// </summary>summary>
        internal BamlRecord GetNextRecord()
        {
            BamlRecord bamlRecord = null;
 
            if (null == PreParsedRecordsStart)
            {
                Stream stream = BinaryReader.BaseStream;
 
                // If we have a ReaderStream we know we are coming from XAML (check if can read full record)
                // When reading BAML we don't get a ReaderStream so:
                //      network - should check for number of bits downloaded but currently
                //          no way to get this information. For now read sync.
                //          NOTE:  This has to be addressed if we want async download
                //                 of BAML.
                //      local file - in memory or something, so else read the record sync.
 
                if (null != XamlReaderStream)
                {
                    long currentPosition = stream.Position;
                    long bytesAvailable = stream.Length - currentPosition;
 
                    // Make sure there is room for the record type in the stream.
                    if (BamlRecord.RecordTypeFieldLength > bytesAvailable)
                    {
                        return null;
                    }
 
                    BamlRecordType recordType = (BamlRecordType)BinaryReader.ReadByte();
 
                    // We've read the record type, so decrement available bytes.
                    bytesAvailable -= BamlRecord.RecordTypeFieldLength;
 
                    // call GetNextRecord passing in the record type.  If this returns null,
                    // then the complete record was not yet available and could not be
                    // read.
                    bamlRecord = ReadNextRecordWithDebugExtension(bytesAvailable, recordType);
 
                    if (bamlRecord == null)
                    {
#if DEBUG
                        // this case can happen if doing BAML Async and entire record hasn't
                        // been downloaded.
                        Debug.Assert(false == XamlReaderStream.IsWriteComplete,
                                "not enough bytes for RecordSize but write is complete");
#endif
                        stream.Seek(currentPosition,SeekOrigin.Begin);
                        return null;
                    }
 
                    // tell stream we are done with these file bits.
                    XamlReaderStream.ReaderDoneWithFileUpToPosition(stream.Position -1);
                }
                else
                {
                    // default to reading a single record synchronous.  Don't attempt
                    // to read if its already at the end of the stream.
                    bool keepOnReading = true;
                    while (keepOnReading)
                    {
                        if (BinaryReader.BaseStream.Length >
                            BinaryReader.BaseStream.Position)
                        {
                            // If we are supposed to skip info records, then just advance the stream
                            // for info records and continue until we get a non-info record, or we
                            // run out of stream data to read.
                            BamlRecordType recordType = (BamlRecordType)BinaryReader.ReadByte();
                            bamlRecord = ReadNextRecordWithDebugExtension(Int64.MaxValue, recordType);
                            keepOnReading = false;
                        }
                        else
                        {
                            keepOnReading = false;
                        }
                    }
                }
            }
            else if (PreParsedCurrentRecord != null) // If the preparsed list has not reached its end
            {
                bamlRecord = PreParsedCurrentRecord;   // return the record pointed to index
                PreParsedCurrentRecord = PreParsedCurrentRecord.Next;
 
                // if the next record is a debug record then process it and advance over it.
                // The Debug record extension record is process BEFORE the current record because
                // it is debug information regarding the current record.
                if (BamlRecordHelper.HasDebugExtensionRecord(ParserContext.IsDebugBamlStream, bamlRecord))
                {
                    ProcessDebugBamlRecord(PreParsedCurrentRecord);
                    PreParsedCurrentRecord = PreParsedCurrentRecord.Next;
                }
            }
            return bamlRecord;
        }
 
        internal BamlRecord ReadNextRecordWithDebugExtension(
            long           bytesAvailable,
            BamlRecordType recordType)
        {
            BamlRecord bamlRecord = BamlRecordManager.ReadNextRecord(BinaryReader, bytesAvailable, recordType);
            if (IsDebugBamlStream)
            {
                if (BamlRecordHelper.DoesRecordTypeHaveDebugExtension(bamlRecord.RecordType))
                {
                    BamlRecord debugExtensionRecord = ReadDebugExtensionRecord();
                    bamlRecord.Next = debugExtensionRecord;
                }
            }
            return bamlRecord;
        }
 
        internal BamlRecord ReadDebugExtensionRecord()
        {
            Stream stream = BinaryReader.BaseStream;
            long bytesAvailable = stream.Length - stream.Position;
            if(bytesAvailable == 0)
                return null;
 
            BamlRecordType nextRecordType = (BamlRecordType)BinaryReader.ReadByte();
 
            if (BamlRecordHelper.IsDebugBamlRecordType(nextRecordType))
            {
                BamlRecord debugBamlRecord = BamlRecordManager.ReadNextRecord(BinaryReader, bytesAvailable, nextRecordType);
                ProcessDebugBamlRecord(debugBamlRecord);
                return debugBamlRecord;
            }
            else
            {
                // if it wasn't a debug record then backup.
                stream.Seek( -1, SeekOrigin.Current);
                return null;
            }
        }
 
        internal void ProcessDebugBamlRecord(BamlRecord bamlRecord)
        {
            if(bamlRecord.RecordType == BamlRecordType.LineNumberAndPosition)
            {
                BamlLineAndPositionRecord bamlLineAndPositionRecord = (BamlLineAndPositionRecord)bamlRecord;
                LineNumber = (int)bamlLineAndPositionRecord.LineNumber;
                LinePosition = (int)bamlLineAndPositionRecord.LinePosition;
            }
            else
            {
                Debug.Assert(bamlRecord.RecordType == BamlRecordType.LinePosition);
                BamlLinePositionRecord bamlLinePositionRecord = (BamlLinePositionRecord)bamlRecord;
                LinePosition = (int)bamlLinePositionRecord.LinePosition;
            }
        }
 
        /// <summary>
        /// Gets the type of the record at the current position of the reader.
        /// </summary>
        internal BamlRecordType GetNextRecordType()
        {
            BamlRecordType bamlRecordType;
 
            if (null == PreParsedRecordsStart)
            {
                bamlRecordType = (BamlRecordType)BinaryReader.PeekChar();
            }
            else
            {
                bamlRecordType = PreParsedCurrentRecord.RecordType;
            }
 
            return bamlRecordType;
        }
 
        /// <summary>
        /// Close the underlying baml stream
        /// </summary>
        internal void Close()
        {
            if (BamlStream != null)
            {
                BamlStream.Close();
            }
            EndOfDocument = true;
        }
 
        /// <summary>
        /// Read the Baml and buld a Tree.
        /// </summary>
        internal bool Read(bool singleRecord)
        {
            BamlRecord bamlRecord = null;
            bool moreData = true;
 
            // loop through the records until the end building the Tree.
            while ( (true == moreData)
                && null != (bamlRecord = GetNextRecord()))
            {
                moreData = ReadRecord(bamlRecord);
 
                // if singleRecordMode then break
                if (singleRecord)
                {
                    break;
                }
            }
 
            // if next bamlRecord read comes back null
            // then moreData is false
            if (null == bamlRecord)
            {
                moreData = false;
            }
 
            // return true for more data meaning it is worth calling
            // read again if in Single Record mode. May or may not
            // really be another record.
 
            return moreData;
        }
 
        /// <summary>
        /// Synchronous read from Baml
        /// </summary>
        internal bool Read()
        {
            return Read(false); // not in single record mode.
        }
 
        /// <summary>
        /// Synchronous read callback that passes line information from original xaml file.
        /// This line information is used when reporting errors.  Make certain that the
        /// parser context line numbers are correct, since this is passed to subparsers and
        /// serializers and they may wish to report line information also.
        /// </summary>
        internal bool Read(
            BamlRecord bamlRecord,
            int        lineNumber,
            int        linePosition)
        {
            LineNumber = lineNumber;
            LinePosition = linePosition;
 
            return ReadRecord(bamlRecord);
        }
 
        internal void ReadVersionHeader()
        {
            BamlVersionHeader version = new BamlVersionHeader();
            version.LoadVersion(BinaryReader);
        }
 
        /// <summary>
        /// Read the Baml starting at the current location until the end of this
        /// element scope has been reached.  Return the object parsed.
        /// </summary>
        /// <remarks>
        /// Note that the first record read MUST be a BamlElementStartRecord, and
        /// reading will continue until the matching BamlElementEndRecord is reached.
        ///
        /// The dictionaryKey property, if set, indicates that this element is in a
        /// dictionary, and this was the key used to identify it.  This is used to
        /// provide better exception messages for deferred instantiation from a dictionary.
        /// </remarks>
        internal object ReadElement(Int64 startPosition,
                                    XamlObjectIds contextXamlObjectIds,
                                    object dictionaryKey )
        {
            BamlRecord bamlRecord = null;
            bool moreData = true;
            BinaryReader.BaseStream.Position = startPosition;
            int elementDepth = 0;
            object data = null;
            bool isKeySetInContext = false;
 
            // Push a special context onto the stack that is used as a placeholder
            // for surrounding context information about this element.
 
            PushContext(ReaderFlags.RealizeDeferContent, null, null, 0);
            CurrentContext.ElementNameOrPropertyName = contextXamlObjectIds.Name;
            CurrentContext.Uid = contextXamlObjectIds.Uid;
            CurrentContext.Key = dictionaryKey;
 
            #if DEBUG
            int stackDepth = ReaderContextStack.Count;
            #endif
 
            // Loop through the records until the matching end record is reached.
            while ( moreData
                && null != (bamlRecord = GetNextRecord()))
            {
                // Count start and end records and stop when we've reached the end
                // record associated with the first start record.  Note that
                // serializers handle the end record, so don't increment the element
                // depth for types that have serializers (such as styles).
                BamlElementStartRecord startRecord = bamlRecord as BamlElementStartRecord;
                if (startRecord != null)
                {
                    if (!MapTable.HasSerializerForTypeId(startRecord.TypeId))
                    {
                        elementDepth++;
                    }
                }
                else if (bamlRecord is BamlElementEndRecord)
                {
                    elementDepth--;
                }
 
                moreData = ReadRecord(bamlRecord);
 
                // If we got a key from the caller, it indicates that this element is being
                // defer-loaded from a dictionary, and this was the element's key.  Set it into
                // the context, as would happen in the non-deferred case, so that it is available to
                // make a good exception message.
 
                if( !isKeySetInContext )
                {
                    CurrentContext.Key = dictionaryKey;
                    isKeySetInContext = true;
                }
 
                // if singleRecordMode then break
                if (elementDepth == 0)
                {
                    break;
                }
            }
 
            // Get the element out of the context, then restore it
            // to null (as it was from the PushContext above).
 
            data = CurrentContext.ObjectData;
            CurrentContext.ObjectData = null;
 
            #if DEBUG  // ifdef's around Debug.Assert are necessary because stackDepth is only DEBUG defined
            Debug.Assert( stackDepth == ReaderContextStack.Count );
            #endif
 
            PopContext();
 
            MapTable.ClearConverterCache();
 
            return data;
        }
 
        protected virtual void ReadConnectionId(BamlConnectionIdRecord bamlConnectionIdRecord)
        {
            // Hookup any IDs or events that correspond to this connectionId on the component
            if (_componentConnector != null)
            {
                object target = GetCurrentObjectData();
                Debug.Assert(bamlConnectionIdRecord.ConnectionId > 0);
                _componentConnector.Connect(bamlConnectionIdRecord.ConnectionId, target);
            }
        }
 
        void ReadDocumentStartRecord(BamlDocumentStartRecord documentStartRecord)
        {
            IsDebugBamlStream = documentStartRecord.DebugBaml;
        }
 
        void ReadDocumentEndRecord()
        {
            Debug.Assert(0 == ReaderContextStack.Count); // if not zero we missed an EndElement
            SetPropertyValueToParent(false /*fromStartTag*/);
            ParserContext.RootElement = null;
            MapTable.ClearConverterCache();
            EndOfDocument = true;
        }
 
        // Read a single record and process it.  Return false if there are no
        // more records to process.
        internal virtual bool ReadRecord(BamlRecord bamlRecord)
        {
            bool moreData = true;
 
#if !STRESS
            try
            {
#endif
                switch (bamlRecord.RecordType)
                {
                    case BamlRecordType.DocumentStart:
                        ReadDocumentStartRecord((BamlDocumentStartRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.DocumentEnd:
                        ReadDocumentEndRecord();
                        moreData = false;
                        break;
 
                    case BamlRecordType.XmlnsProperty:
                        ReadXmlnsPropertyRecord((BamlXmlnsPropertyRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.PIMapping:
                        {
                            // If this mapping has not already been set up, then set it now
                            BamlPIMappingRecord piMappingRecord = (BamlPIMappingRecord)bamlRecord;
                            if (!XamlTypeMapper.PITable.Contains(piMappingRecord.XmlNamespace))
                            {
                                BamlAssemblyInfoRecord assemblyInfo = MapTable.GetAssemblyInfoFromId(piMappingRecord.AssemblyId);
                                // Add information to the MappingPI hashtable
                                ClrNamespaceAssemblyPair mapping = new ClrNamespaceAssemblyPair(
                                                                        piMappingRecord.ClrNamespace,
                                                                        assemblyInfo.AssemblyFullName);
                                XamlTypeMapper.PITable.Add(piMappingRecord.XmlNamespace, mapping);
                            }
                            break;
                        }
 
                    case BamlRecordType.AssemblyInfo:
                        MapTable.LoadAssemblyInfoRecord((BamlAssemblyInfoRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.TypeInfo:
                    case BamlRecordType.TypeSerializerInfo:
                        MapTable.LoadTypeInfoRecord((BamlTypeInfoRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.AttributeInfo:
                        MapTable.LoadAttributeInfoRecord((BamlAttributeInfoRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.StringInfo:
                        MapTable.LoadStringInfoRecord((BamlStringInfoRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.LiteralContent:
                        ReadLiteralContentRecord((BamlLiteralContentRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.ElementStart:
                    case BamlRecordType.StaticResourceStart:
                        if (((BamlElementStartRecord)bamlRecord).IsInjected)
                        {
                            CurrentContext.SetFlag(ReaderFlags.InjectedElement);
                        }
                        else
                        {
                            ReadElementStartRecord((BamlElementStartRecord)bamlRecord);
                        }
                        break;
 
                    case BamlRecordType.NamedElementStart:
                        // This is only used by template code, and only as a temporary record, so should never occur here.
                        // See comment on BamlNamedElementStartRecord
                        Debug.Assert(false);
                        break;
 
                    case BamlRecordType.ConnectionId:
                        ReadConnectionId((BamlConnectionIdRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.ElementEnd:
                    case BamlRecordType.StaticResourceEnd:
                        if (CurrentContext.CheckFlag(ReaderFlags.InjectedElement))
                        {
                            CurrentContext.ClearFlag(ReaderFlags.InjectedElement);
                        }
                        else
                        {
                            ReadElementEndRecord(false);
                        }
                        break;
 
                    case BamlRecordType.PropertyComplexStart:
                        ReadPropertyComplexStartRecord((BamlPropertyComplexStartRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.PropertyComplexEnd:
                        ReadPropertyComplexEndRecord();
                        break;
 
                    case BamlRecordType.Property:
                        ReadPropertyRecord((BamlPropertyRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.PropertyStringReference:
                        ReadPropertyStringRecord((BamlPropertyStringReferenceRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.PropertyTypeReference:
                        ReadPropertyTypeRecord((BamlPropertyTypeReferenceRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.PropertyWithExtension:
                        ReadPropertyWithExtensionRecord((BamlPropertyWithExtensionRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.PropertyWithConverter:
                        ReadPropertyConverterRecord((BamlPropertyWithConverterRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.PropertyCustom:
                        ReadPropertyCustomRecord((BamlPropertyCustomRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.PropertyArrayStart:
                        ReadPropertyArrayStartRecord((BamlPropertyArrayStartRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.PropertyArrayEnd:
                        ReadPropertyArrayEndRecord();
                        break;
 
                    case BamlRecordType.PropertyIListStart:
                        ReadPropertyIListStartRecord((BamlPropertyIListStartRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.PropertyIListEnd:
                        ReadPropertyIListEndRecord();
                        break;
 
                    case BamlRecordType.PropertyIDictionaryStart:
                        ReadPropertyIDictionaryStartRecord((BamlPropertyIDictionaryStartRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.PropertyIDictionaryEnd:
                        ReadPropertyIDictionaryEndRecord();
                        break;
 
                    case BamlRecordType.DefAttribute:
                        ReadDefAttributeRecord((BamlDefAttributeRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.DefAttributeKeyType:
                        ReadDefAttributeKeyTypeRecord((BamlDefAttributeKeyTypeRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.PresentationOptionsAttribute:
                        ReadPresentationOptionsAttributeRecord((BamlPresentationOptionsAttributeRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.RoutedEvent:
                        {
                            Debug.Assert(ReaderFlags.DependencyObject == CurrentContext.ContextType);
                            DependencyObject currentParent = GetCurrentObjectData() as DependencyObject;
                            BamlRoutedEventRecord bamlRoutedEventRecord = (BamlRoutedEventRecord)bamlRecord;
 
                            ThrowException(nameof(SR.ParserBamlEvent), bamlRoutedEventRecord.Value);
                        }
                        break;
 
                    case BamlRecordType.Text:
                    case BamlRecordType.TextWithId:
                    case BamlRecordType.TextWithConverter:
                        ReadTextRecord((BamlTextRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.DeferableContentStart:
                        ReadDeferableContentStart((BamlDeferableContentStartRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.KeyElementStart:
                        ReadKeyElementStartRecord((BamlKeyElementStartRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.KeyElementEnd:
                        ReadKeyElementEndRecord();
                        break;
 
                    case BamlRecordType.ConstructorParametersStart:
                        ReadConstructorParametersStartRecord();
                        break;
 
                    case BamlRecordType.ConstructorParametersEnd:
                        ReadConstructorParametersEndRecord();
                        break;
 
                    case BamlRecordType.ConstructorParameterType:
                        ReadConstructorParameterTypeRecord((BamlConstructorParameterTypeRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.ContentProperty:
                        ReadContentPropertyRecord((BamlContentPropertyRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.StaticResourceId:
                        ReadStaticResourceIdRecord((BamlStaticResourceIdRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.PropertyWithStaticResourceId:
                        ReadPropertyWithStaticResourceIdRecord((BamlPropertyWithStaticResourceIdRecord)bamlRecord);
                        break;
 
                    case BamlRecordType.LineNumberAndPosition:  // Should be skipped in ReadNextRecordWithDebugExtension.
                    case BamlRecordType.LinePosition:           // Should be skipped in ReadNextRecordWithDebugExtension.
                    default:
                        ThrowException(nameof(SR.ParserUnknownBaml), ((int)bamlRecord.RecordType).ToString(CultureInfo.CurrentCulture));
                        break;
                }
 
#if !STRESS
            }
 
            catch (Exception e)
            {
                // Don't wrap critical exceptions or already-wrapped exceptions.
                if (CriticalExceptions.IsCriticalException(e) || e is XamlParseException )
                {
                    throw;
                }
 
                XamlParseException.ThrowException( ParserContext,
                                               LineNumber,
                                               LinePosition,
                                               String.Empty /*message*/,
                                               e );
            }
#endif
            return moreData;
        }
 
        // Read an XML namespace definition record.  This contains a mapping from
        // an xml namespace to a prefix used within the scope of the current element.
        protected virtual void ReadXmlnsPropertyRecord(BamlXmlnsPropertyRecord xmlnsRecord)
        {
            Debug.Assert(ReaderFlags.DependencyObject == CurrentContext.ContextType ||
                ReaderFlags.ClrObject == CurrentContext.ContextType ||
                ReaderFlags.PropertyComplexClr == CurrentContext.ContextType ||
                ReaderFlags.PropertyComplexDP == CurrentContext.ContextType);
 
            // Accept name space directives for DependencyObjects and clr objects only
            if (ReaderFlags.DependencyObject == CurrentContext.ContextType ||
                ReaderFlags.ClrObject == CurrentContext.ContextType ||
                ReaderFlags.PropertyComplexClr == CurrentContext.ContextType ||
                ReaderFlags.PropertyComplexDP == CurrentContext.ContextType)
            {
                XmlnsDictionary[xmlnsRecord.Prefix] = xmlnsRecord.XmlNamespace;
 
                XamlTypeMapper.SetUriToAssemblyNameMapping(xmlnsRecord.XmlNamespace, xmlnsRecord.AssemblyIds);
 
                // Making this call will populate XamlTypeMapper.NamespaceMapHashList
                //  with appropriate values for this namespace URI.
                // We do this here because we need to save this data now to make it
                //  available later for XamlTypeMapper.GetTypeFromName() which gets it
                //  as value of XmlAttributeProperties.XmlNamespaceMapsProperty.
 
         // XamlTypeMapper.GetNamespaceMapEntries(xmlnsRecord);
 
                if (ReaderFlags.DependencyObject == CurrentContext.ContextType)
                {
                    SetXmlnsOnCurrentObject(xmlnsRecord);
                }
            }
        }
 
        // Determine the element type for a baml start record, and either create a new
        // element or mark it for delay creation later.  Update the ReaderFlags to
        // indicate the type of element created.
        private void GetElementAndFlags(
                BamlElementStartRecord bamlElementStartRecord,
                out object element,
                out ReaderFlags flags,
                out Type delayCreatedType,
                out short delayCreatedTypeId)
        {
            short typeId = bamlElementStartRecord.TypeId;
            Type elementType = MapTable.GetTypeFromId(typeId);
            element = null;
 
            delayCreatedType = null;
            delayCreatedTypeId = 0;
            flags = ReaderFlags.Unknown;
 
            if (null != elementType)
            {
                if (bamlElementStartRecord.CreateUsingTypeConverter ||
                    typeof(MarkupExtension).IsAssignableFrom(elementType))
                {
                    // CreateUsingTypeConverter means we've decided
                    //  (in XamlRecordReader) that we do not wish to
                    //  create an instance at this time, go to the delay-
                    //  creation state.
                    // MarkupExtensions will be created later after we have
                    //  parsed the constructor parameters.
                    delayCreatedType = elementType;
                    delayCreatedTypeId = typeId;
                }
                else
                {
                    // Create an instance of the object specified by the
                    //  BeginElement, throw if the creation fails.
                    element = CreateInstanceFromType(elementType, typeId, false);
                    if (element == null)
                    {
                        ThrowException(nameof(SR.ParserNoElementCreate2), elementType.FullName);
                    }
                }
 
                flags = GetFlagsFromType(elementType);
            }
        }
 
        // Sets the ReaderFlags based on whether the elementType passed in is one of the special
        // collection types and whether the type is a DependencyObject or not.
        protected ReaderFlags GetFlagsFromType(Type elementType)
        {
            ReaderFlags flags = (typeof(DependencyObject).IsAssignableFrom(elementType) ? ReaderFlags.DependencyObject :
                                                                                          ReaderFlags.ClrObject);
 
            if (typeof(IDictionary).IsAssignableFrom(elementType))
            {
                flags |= ReaderFlags.IDictionary;
            }
            else if (typeof(IList).IsAssignableFrom(elementType))
            {
                flags |= ReaderFlags.IList;
            }
            else if (typeof(ArrayExtension).IsAssignableFrom(elementType))
            {
                flags |= ReaderFlags.ArrayExt;
            }
            else if (BamlRecordManager.TreatAsIAddChild(elementType))
            {
                flags |= ReaderFlags.IAddChild;
            }
 
            return flags;
        }
 
        // Modify the passed flags to set the NeedToAddToTree flag based on the current
        // context.  This is needed by subparsers in some cases.
        internal static void CheckForTreeAdd(ref ReaderFlags flags, ReaderContextStackData context)
        {
            // An element doesn't need to be added to a tree if in the context of constructor
            // paramters or deferred content
 
            if (context == null ||
                (context.ContextType != ReaderFlags.ConstructorParams &&
                 context.ContextType != ReaderFlags.RealizeDeferContent))
            {
                flags |= ReaderFlags.NeedToAddToTree;
            }
        }
 
        //+-----------------------------------------------------------------------------------------------------------------------
        //
        //  SetDependencyValue
        //
        //  We call this routine to set a DP value onto a DO, but it's virtual so that custom baml record readers
        //  can do their own thing.  This was added so that templates could set unshareable template child property
        //  values into per-FE state.
        //
        //+-----------------------------------------------------------------------------------------------------------------------
 
        internal void SetDependencyValue(DependencyObject dependencyObject, DependencyProperty dependencyProperty, object value)
        {
            // We don't need to get the metadata if we aren't skipping journaled properties
            FrameworkPropertyMetadata metadata = ParserContext != null && ParserContext.SkipJournaledProperties ?
                dependencyProperty.GetMetadata(dependencyObject.DependencyObjectType) as FrameworkPropertyMetadata
                : null;
 
            // If the metadata is not null here, we are skipping journaled properties (if the metadata requires it)
            // NOTE: we do not journal expression. So even when the property is journalable but the value is expression,
            // we still want to set the value from parser. See corresponding code for avoiding saving expression in DataStream.SaveSubStreams.
            if ((metadata == null) || (!metadata.Journal) || (value is Expression))
            {
                SetDependencyValueCore(dependencyObject, dependencyProperty, value);
            }
        }
 
        internal virtual void SetDependencyValueCore(DependencyObject dependencyObject, DependencyProperty dependencyProperty, object value)
        {
            // By default, we just set the DP on the DO.
            dependencyObject.SetValue(dependencyProperty, value);
        }
 
        //+-----------------------------------------------------------------------------------------------------------------------
        //
        //  ProvideValueFromMarkupExtension
        //
        //  Given a MarkupExtension, call its ProvideValue, passing it the right IServiceProvider.
        //
        //+-----------------------------------------------------------------------------------------------------------------------
 
        internal object ProvideValueFromMarkupExtension(MarkupExtension markupExtension, object obj, object member)
        {
            object returnValue = null;
 
            // Get the IServiceProvider
            ProvideValueServiceProvider serviceProvider = ParserContext.ProvideValueProvider;
 
            // Let it know the target object & property
            serviceProvider.SetData(obj, member);
 
            try
            {
                returnValue = markupExtension.ProvideValue(serviceProvider);
 
                if( TraceMarkup.IsEnabled )
                {
                    TraceMarkup.TraceActivityItem(
                                          TraceMarkup.ProvideValue,
                                          markupExtension,
                                          obj,
                                          member,
                                          returnValue );
                }
            }
            finally
            {
                serviceProvider.ClearData();
            }
 
            return returnValue;
        }
 
        // Read the start of an element.  This involves creating a new object, and storing it
        // for later addition to the tree or setting as a property.  The base method does
        // not check for a serializer.
        internal void BaseReadElementStartRecord(
            BamlElementStartRecord bamlElementRecord)
        {
            object        element = null;
            Type          delayCreatedType = null;
            short         delayCreatedTypeId = 0;
            ReaderFlags   flags = ReaderFlags.Unknown;
            ReaderContextStackData currentContext = CurrentContext;
 
            if (_bamlAsForest && currentContext == null)
            {
                Debug.Assert(_rootElement != null);
                element = _rootElement;
 
                flags = GetFlagsFromType(element.GetType());
            }
            else
            {
                if (null != currentContext &&
                    (ReaderFlags.PropertyComplexClr == currentContext.ContextType ||
                     ReaderFlags.PropertyComplexDP == currentContext.ContextType) &&
                    null == currentContext.ExpectedType)
                {
                    string propName = GetPropNameFrom(currentContext.ObjectData);
                    ThrowException(nameof(SR.ParserNoComplexMulti), propName);
                }
 
                // If this is the very top element as indicated by there not being a
                // parent context, then we have to add this element to the rootlist
                // by calling SetPropertyValueToParent.  For all other cases we don't want to
                // call this here since we may be building a subtree bottom up and want
                // to defer addition of elements.  
                if (null == ParentContext)
                {
                    SetPropertyValueToParent(true);
                }
 
                // Get an instance of the element, if it is to be created now.  Also set
                // the flags to indicate what the element is and how to treat it.
                GetElementAndFlags(bamlElementRecord, out element, out flags,
                                   out delayCreatedType, out delayCreatedTypeId);
            }
 
            Stream bamlStream = BamlStream;
 
            if (!_bamlAsForest &&
                currentContext == null &&
                element != null &&
                bamlStream != null &&
                !(bamlStream is ReaderStream) &&
                StreamPosition == StreamLength)
            {
                // We are here because the root element was loaded from this baml stream
                // and not passed to us as is the case with the app loader\navigation engine,
                // and we are already at the end of the stream while processing this start
                // element record which would be the case when we have an element that has already
                // been instantiated by an inner LoadBaml call for that element with the same
                // Uri\ResourceLocator. So in this case we need to simulate a DocumentEnd to
                // cleanup properly and add to the RootList so that the caller of the outer
                // LoadBaml can access the element created by the inner LoadBaml.
 
                Debug.Assert(null == ParentContext);
 
                ReadDocumentEndRecord();
                if (RootList.Count == 0)
                {
                    RootList.Add(element);
                }
 
                // Set a flag to prevent the TreeBuilder from clobbering the
                // XamlTypeMapper's xmlns hashtable on the root element as this
                // would have already been set by the inner Baml loading Context.
                IsRootAlreadyLoaded = true;
            }
            else
            {
                // If we have a real element at this point, instead of some object that will be
                // delay created later, check for various interfaces that are called upon
                // element creation.
                if (element != null)
                {
                    // If this is an element start record that carries its name also, then register the name now also.
                    string elementName = null;
 
                    if (bamlElementRecord is BamlNamedElementStartRecord)
                    {
                        BamlNamedElementStartRecord bamlNamedElementStartRecord = bamlElementRecord as BamlNamedElementStartRecord;
                        elementName = bamlNamedElementStartRecord.RuntimeName;
                    }
 
                    ElementInitialize(element, elementName);
                }
 
 
                // Remember the object that was just created.  It will be added when
                // the end tag is reached.
                CheckForTreeAdd(ref flags, currentContext);
                PushContext(flags, element, delayCreatedType, delayCreatedTypeId, bamlElementRecord.CreateUsingTypeConverter);
 
 
                // Add just constructed element to the tree if it is a UIElement.  This
                // builds the tree in a top-down fashion for objects that make up the majority
                // of the logical tree.  Other objects, such as Freezables, are added bottom-up
                // to aid in having all properties set prior to adding them to the tree.
                // See PS workitem #19080
                if (BuildTopDown &&
                    element != null &&
                    ((element is UIElement) ||
                    (element is ContentElement) ||
                    (element is UIElement3D)))
                {
                    SetPropertyValueToParent(true);
                }
                else if (CurrentContext.CheckFlag(ReaderFlags.IDictionary))
                {
                    // AddElement to Tree checks this, but if that wasn't called, then we need
                    // to check for an explicit tag after a dictionary property.
                    bool isMarkupExtension = false;
                    if (CheckExplicitCollectionTag(ref isMarkupExtension))
                    {
                        // if the tag is an explicit element under a collection property, we're done
                        CurrentContext.MarkAddedToTree();
 
                        // ResourceDictionary objects must be loaded top-down
                        if (element is ResourceDictionary)
                        {
                            SetCollectionPropertyValue(ParentContext);
                        }
                    }
                }
            }
        }
 
        // Read the start of an element.  This involves creating a new object, and storing it
        // for later addition to the tree or setting as a property.
        // Return true if a serializer has been spun off to parse the next element, or
        // false if it was handled by the BamlRecordReader itself.  If a serializer has
        // been spun off, then the end record that matches this start record will NOT
        // get to this instance of the BamlRecordReader.
        protected virtual bool ReadElementStartRecord(BamlElementStartRecord bamlElementRecord)
        {
            // Check if the type of this element has a serializer associated with it.  If so then
            // we have to create a serializer and pass off processing to it.  Otherwise, continue
            // with default processing.
            bool hasSerializer = MapTable.HasSerializerForTypeId(bamlElementRecord.TypeId);
            if (hasSerializer)
            {
                EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose, EventTrace.Event.WClientParseRdrCrInstBegin);
 
                try
                {
                    BamlTypeInfoRecord typeInfo = MapTable.GetTypeInfoFromId(bamlElementRecord.TypeId);
                    XamlSerializer serializer = CreateSerializer((BamlTypeInfoWithSerializerRecord)typeInfo);
 
                    if (ParserContext.RootElement == null)
                    {
                        ParserContext.RootElement = _rootElement;
                    }
                    if (ParserContext.StyleConnector == null)
                    {
                        ParserContext.StyleConnector = _rootElement as IStyleConnector;
                    }
 
                    // PreParsedIndex is updated by Serializer after its TreeBuilder.Parse.
                    serializer.ConvertBamlToObject(this, bamlElementRecord, ParserContext);
                }
                finally
                {
                    EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose, EventTrace.Event.WClientParseRdrCrInstEnd);
                }
                return true;
            }
 
            BaseReadElementStartRecord(bamlElementRecord);
            return false;
        }
 
        // The end of an element has been reached.  What to do depends on the current
        // context, since the object may be added as a child to another object, placed in
        // in a dictionary, added to a list, set as a property, etc...
        protected internal virtual void ReadElementEndRecord(bool fromNestedBamlRecordReader)
        {
            if (null == CurrentContext ||
                (ReaderFlags.DependencyObject != CurrentContext.ContextType &&
                 ReaderFlags.ClrObject != CurrentContext.ContextType))
            {
                ThrowException(nameof(SR.ParserUnexpectedEndEle));
            }
 
            object currentElement = GetCurrentObjectData();
 
            // Make sure we have called EndInit on the currentElement before it is set
            // as a property value on the parent. This is because if we encounter an
            // exception during the call to EndInit we want to be able to use the
            // Fallback provided by the parent for the given property. So in order to
            // set the right property value on the parent we should have called EndInit
            // prior to the call to SetPropertyValueToParent. Example
            //
            // <Image>
            // <Image.Source>
            //   <BitmapImage UriSource="c:\\bogus.jpg" />
            // </Image.Source>
            // </Image>
            //
            // Calling EndInit on BitmapImage throws and exception and then we need to
            // use the Fallback provided by Image for the Source property.
 
            ElementEndInit(ref currentElement);
 
            // Check if the element on the stack needs to be added to the tree as a child
            // If not, then continue and see if the element should be added to a list, dictionary,
            // array, set as a property value, etc.
            SetPropertyValueToParent(false /*fromStartTag*/);
 
            Debug.Assert(!CurrentContext.CheckFlag(ReaderFlags.NeedToAddToTree), "Failed to add Element to tree before popping stack");
 
            ReaderFlags flags = CurrentContext.ContextFlags;
 
            FreezeIfRequired(currentElement);
 
            // pop the stack
            PopContext();
 
            // Deferred content and constructor parameters aren't handled in SetPropertyValueToParent
 
            if ((flags & (ReaderFlags.AddedToTree)) == 0 &&
                CurrentContext != null)
            {
                Debug.Assert( CurrentContext.ContextType != ReaderFlags.PropertyComplexClr );
                Debug.Assert( CurrentContext.ContextType != ReaderFlags.PropertyComplexDP );
 
                switch (CurrentContext.ContextType)
                {
                    case ReaderFlags.RealizeDeferContent:
                        // Pass the object up
                        CurrentContext.ObjectData = currentElement;
                        break;
 
                    case ReaderFlags.ConstructorParams:
                        SetConstructorParameter(currentElement);
                        break;
                }
            }
        }
 
 
        // Read the start of an element that is the first
        // object in a key in a resource dictionary.
        internal virtual void ReadKeyElementStartRecord(
            BamlKeyElementStartRecord bamlElementRecord)
        {
            Type elementType = MapTable.GetTypeFromId(bamlElementRecord.TypeId);
 
            ReaderFlags flags  = (elementType.IsAssignableFrom(typeof(DependencyObject)) ?
                                               ReaderFlags.DependencyObject :
                                               ReaderFlags.ClrObject) |
                                               ReaderFlags.NeedToAddToTree;
 
            // Remember the object that was just created.  It will be used when
            // the end tag is reached and the key is complete
            PushContext(flags, null, elementType, bamlElementRecord.TypeId);
        }
 
        // The end of an element that represents a key in an IDictionary has
        // been reached.  Search for the dictionary holder in the reader stack
        // and set the key value to the current object on the top of the
        // reader stack.
        internal virtual void ReadKeyElementEndRecord()
        {
            object key = ProvideValueFromMarkupExtension((MarkupExtension)GetCurrentObjectData(),
                                                         ParentObjectData, null /*member*/);
 
            SetKeyOnContext(key, XamlReaderHelper.DefinitionName, ParentContext, GrandParentContext);
            PopContext();
        }
 
        // The constructor parameter with a single Type object has been read in.  Get the
        // type associated with this record and add it to the constructor parameter list.
        internal virtual void ReadConstructorParameterTypeRecord(
            BamlConstructorParameterTypeRecord constructorParameterType)
        {
            Debug.Assert(CurrentContext.ContextType == ReaderFlags.ConstructorParams);
            SetConstructorParameter(MapTable.GetTypeFromId(constructorParameterType.TypeId));
        }
 
        // Read the content property record and set the ContentProperty in the context.
        internal virtual void ReadContentPropertyRecord(
            BamlContentPropertyRecord bamlContentPropertyRecord)
        {
            object contentProperty = null;
 
            short attributeId = bamlContentPropertyRecord.AttributeId;
 
            // Try KnownTypes Optimization: When the property is known use generated code for accessing it
            object parent = GetCurrentObjectData();
            if (parent != null)
            {
                short elementId = BamlMapTable.GetKnownTypeIdFromType(parent.GetType());
                if (elementId < 0)
                {
                    contentProperty = KnownTypes.GetCollectionForCPA(parent, (KnownElements)(-elementId));
                }
            }
 
            if (contentProperty == null)
            {
                WpfPropertyDefinition propertyDefinition = new WpfPropertyDefinition(this, attributeId, parent is DependencyObject);
 
                // Try DependencyProperty Optimization: When a DP exists for the property, use it for accessing the property
                if (propertyDefinition.DependencyProperty != null)
                {
                    Debug.Assert(parent is DependencyObject);
 
                    if (typeof(IList).IsAssignableFrom(propertyDefinition.PropertyType))
                    {
                        contentProperty = ((DependencyObject)parent).GetValue(propertyDefinition.DependencyProperty) as IList;
                        // We assume that the contentProperty will become a collection now.
                        // However, in case when the DP is implemented incorrectly it may return null even if the clr property has non-null value.
                        // So leaving contentProperty==null will drive us to general clr case below, which must do better job.
                    }
                    else
                    {
                        // When the property is not a IList store a DP itself as a contentProperty for assigning a simple value
                        contentProperty = propertyDefinition.DependencyProperty;
                    }
                }
 
                if (contentProperty == null)
                {
                    // We consider only PropertyInfo case here.
                    // We do not consider AttachedPropertySetter in this case because content property cannot be attached.
                    if (propertyDefinition.PropertyInfo != null)
                    {
                        // Try to treat the content property as IList
                        if (propertyDefinition.IsInternal)
                        {
                            contentProperty = XamlTypeMapper.GetInternalPropertyValue(ParserContext,
                                                                                      ParserContext.RootElement,
                                                                                      propertyDefinition.PropertyInfo,
                                                                                      parent) as IList;
 
                            // if Content Property does not support IList, then see if it is
                            // accessible\allowed as a regular setter.
                            if (contentProperty == null)
                            {
                                bool isPublicProperty;
                                bool allowProtected =
                                    (ParserContext.RootElement is IComponentConnector) &&
                                    (ParserContext.RootElement == parent);
                                if (!XamlTypeMapper.IsAllowedPropertySet(propertyDefinition.PropertyInfo, allowProtected, out isPublicProperty))
                                {
                                    ThrowException(nameof(SR.ParserCantSetContentProperty), propertyDefinition.Name, propertyDefinition.PropertyInfo.ReflectedType.Name);
                                }
                            }
                        }
                        else
                        {
                            contentProperty = propertyDefinition.PropertyInfo.GetValue(
                                parent,
                                BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy,
                                null, null, TypeConverterHelper.InvariantEnglishUS)
                                as IList;
                        }
 
                        if (contentProperty == null)
                        {
                            // The property returned null, try setting it directly.
                            contentProperty = propertyDefinition.PropertyInfo;
                        }
                    }
                }
            }
 
            if (contentProperty == null)
            {
                ThrowException(nameof(SR.ParserCantGetDPOrPi), GetPropertyNameFromAttributeId(attributeId));
            }
 
            CurrentContext.ContentProperty = contentProperty;
        }
 
        // The Start of the constructor parameter section has been reached.  Prepare to
        // store all the top level objects that follow up to the ConstructorParametersEnd
        // record is reached.
        internal virtual void ReadConstructorParametersStartRecord()
        {
            PushContext(ReaderFlags.ConstructorParams, null, null, 0);
        }
 
        // The end of the constructor parameter section has been reached.  Create an
        // instance of the object after finding the appropriate constructor and converting
        // all of the objects held on the stack.
        internal virtual void ReadConstructorParametersEndRecord()
        {
            Type   elementType = ParentContext.ExpectedType;
            short  positiveElementTypeId = (short)-ParentContext.ExpectedTypeId;
 
            object param = null;
            ArrayList paramList = null;
            int paramCount;
            object instance = null;
            bool foundInstance = false;
 
            if( TraceMarkup.IsEnabled )
            {
                TraceMarkup.Trace( TraceEventType.Start,
                                 TraceMarkup.CreateMarkupExtension,
                                 elementType );
            }
 
            if (CurrentContext.CheckFlag(ReaderFlags.SingletonConstructorParam))
            {
                param = CurrentContext.ObjectData;
                paramCount = 1;
 
                // Fast code path for [static/dynamic] resource extensions &
                // Type/Static/TemplateBinding extensions
                switch (positiveElementTypeId)
                {
                    case (short)KnownElements.TypeExtension:
 
                        // Note that this assumes that TypeExtension has a
                        // constructor with one param of type Type or String.
                        Type t = param as Type;
                        if (t != null)
                        {
                            instance = new TypeExtension(t);
                        }
                        else
                        {
                            Debug.Assert(param is String);
                            instance = new TypeExtension((String)param);
                        }
 
                        foundInstance = true;
                        break;
 
                    case (short)KnownElements.StaticResourceExtension:
 
                        // Note that this assumes that StaticResourceExtension has a
                        // constructor with one param of type object.
                        instance = new StaticResourceExtension(param);
                        foundInstance = true;
                        break;
 
                    case (short)KnownElements.DynamicResourceExtension:
 
                        // Note that this assumes that DynamicResourceExtension has a
                        // constructor with one param of type object.
                        instance = new DynamicResourceExtension(param);
                        foundInstance = true;
                        break;
 
                    case (short)KnownElements.StaticExtension:
 
                        // Note that this assumes that StaticExtension has a default
                        // constructor and one public property of type string and one
                        // internal property of type object for optimized member info.
                        instance = new StaticExtension((string)param);
                        foundInstance = true;
                        break;
 
                    case (short)KnownElements.TemplateBindingExtension:
 
                        // Note that this assumes that TemplateBindingExtension has a
                        // constructor with one param of type DependencyProperty. If a
                        // string is passed in due to there being other attributes like
                        // converter being set, then that needs to be converted now first.
                        DependencyProperty dp = param as DependencyProperty;
                        if (dp == null)
                        {
                            string paramString = param as string;
                            Type ownerType = ParserContext.TargetType;
                            Debug.Assert(paramString != null);
 
                            dp = XamlTypeMapper.ParsePropertyName(ParserContext,
                                                                  paramString.Trim(),
                                                                  ref ownerType);
 
                            if (dp == null)
                            {
                                ThrowException(nameof(SR.ParserNoDPOnOwner), paramString, ownerType.FullName);
                            }
                        }
 
                        instance = new TemplateBindingExtension(dp);
                        foundInstance = true;
                        break;
                }
            }
            else
            {
                paramList = (ArrayList)CurrentContext.ObjectData;
                paramCount = paramList.Count;
            }
 
            if (!foundInstance)
            {
                // Find the constructor based on the number of parameters stored in paramList
                XamlTypeMapper.ConstructorData data = XamlTypeMapper.GetConstructors(elementType);
                ConstructorInfo[] infos = data.Constructors;
                for (int i=0; i<infos.Length; i++)
                {
                    ConstructorInfo info = infos[i];
                    ParameterInfo[] paramInfos = data.GetParameters(i);
                    if (paramInfos.Length == paramCount)
                    {
                        object[] paramArray = new object[paramInfos.Length];
 
                        if (paramCount == 1)
                        {
                            Debug.Assert(param != null && paramList == null, "Must have a single param");
                            ProcessConstructorParameter(paramInfos[0], param, ref paramArray[0]);
 
                            // Fast code path for other markupextensions
                            if (positiveElementTypeId == (short)KnownElements.RelativeSource)
                            {
                                // Note that this assumes that RelativeSource has a
                                // constructor with one param of type RelativeSourceMode.
                                instance = new System.Windows.Data.RelativeSource((System.Windows.Data.RelativeSourceMode)paramArray[0]);
                                foundInstance = true;
                            }
                        }
                        else
                        {
                            Debug.Assert(param == null && paramList != null, "Must have a paramList");
 
                            // Check each type and attempt to convert the paramList using
                            // the type converter associated with each parameter type.
                            for (int j=0; j<paramInfos.Length; j++)
                            {
                                ProcessConstructorParameter(paramInfos[j], paramList[j], ref paramArray[j]);
                            }
                        }
 
                        if (!foundInstance)
                        {
                            // If we make it to here we have a list of converted parameters, so
                            // invoke the constructor with that list.
#if !STRESS
                            try
                            {
#endif
                                instance = info.Invoke(paramArray);
                                foundInstance = true;
#if !STRESS
                            }
                            catch (Exception e)
                            {
                                if (CriticalExceptions.IsCriticalException(e) || e is XamlParseException)
                                {
                                    throw;
                                }
 
                                TargetInvocationException tie = e as TargetInvocationException;
                                if( tie != null )
                                {
                                    e = tie.InnerException;
                                }
 
                                ThrowExceptionWithLine(SR.Format(SR.ParserFailedToCreateFromConstructor, info.DeclaringType.Name),  e);
                            }
#endif
                        }
                    }
                }
            }
 
            if (foundInstance)
            {
                ParentContext.ObjectData = instance;
                ParentContext.ExpectedType = null;
                PopContext();
            }
            else
            {
                // If we get to here, then no matching constructor was found, so complain
                ThrowException(nameof(SR.ParserBadConstructorParams), elementType.Name, paramCount.ToString(CultureInfo.CurrentCulture));
            }
 
            if( TraceMarkup.IsEnabled )
            {
                TraceMarkup.Trace( TraceEventType.Stop,
                                 TraceMarkup.CreateMarkupExtension,
                                 elementType,
                                 instance );
            }
        }
 
        // Helper that processes a single constructor parameter
        private void ProcessConstructorParameter(ParameterInfo paramInfo, object param, ref object paramArrayItem)
        {
            // Check for MarkupExtensions in the parameter list and
            // get values from those, if available.
            MarkupExtension me = param as MarkupExtension;
            if (me != null)
            {
                param = ProvideValueFromMarkupExtension(me, null, null);
            }
 
            // Don't convert parameters of type object.  Leave them alone.
            if (param != null &&
                paramInfo.ParameterType != typeof(Object) &&
                paramInfo.ParameterType != param.GetType())
            {
                object convertedParam;
 
                TypeConverter converter = XamlTypeMapper.GetTypeConverter(paramInfo.ParameterType);
 
 
                if( TraceMarkup.IsEnabled )
                {
                    TraceMarkup.Trace( TraceEventType.Start,
                                     TraceMarkup.ProcessConstructorParameter,
                                     paramInfo.ParameterType,
                                     converter.GetType(),
                                     param );
                }
 
#if !STRESS
                try
                {
#endif
                    if (param is String)
                    {
                        convertedParam = converter.ConvertFromString(TypeConvertContext,
                                                                TypeConverterHelper.InvariantEnglishUS,
                                                                (param as String));
                        param = convertedParam;
                    }
 
                    else
                    {
                        // Let normal type converter errors occur here, since we are not
                        // dealing with strings.  Don't convert if we already have
                        // the correct types.  Not converting hides bugs in type converters
                        // such as BrushConverter that can't convert a Brush to a Brush.
                        if (!paramInfo.ParameterType.IsAssignableFrom(param.GetType()))
                        {
                            convertedParam = converter.ConvertTo(TypeConvertContext,
                                                       TypeConverterHelper.InvariantEnglishUS,
                                                       param,
                                                       paramInfo.ParameterType);
                            param = convertedParam;
                        }
                    }
#if !STRESS
                }
 
                catch( Exception e )
                {
                    if( CriticalExceptions.IsCriticalException(e) || e is XamlParseException )
                    {
                        throw;
                    }
 
                    ThrowExceptionWithLine(
                                   SR.Format(SR.ParserCannotConvertString,
                                          param.ToString(),
                                          paramInfo.ParameterType.FullName),
                                   e);
                }
#endif
 
                if( TraceMarkup.IsEnabled )
                {
                    TraceMarkup.Trace( TraceEventType.Stop,
                                     TraceMarkup.ProcessConstructorParameter,
                                     paramInfo.ParameterType,
                                     converter.GetType(),
                                     param );
                }
            }
 
            // Copy the contents of paramList into the paramArray
            paramArrayItem = param;
        }
 
        // The start of a block of deferable content has been reached.  There should
        // be a ResourceDictionary above us in the reader stack, so call it
        // with the stream and position information for the deferable block.  Then
        // skip over the deferable block after parsing the key table and continue.
        internal virtual void ReadDeferableContentStart(
            BamlDeferableContentStartRecord bamlRecord)
        {
            ResourceDictionary dictionary = GetDictionaryFromContext(CurrentContext, true /*toInsert*/) as ResourceDictionary;
 
            if (dictionary != null)
            {
                // At present we DO NOT SUPPORT having deferable content in an async
                // stream, since we don't have a good way to defer the load of this block
                // of records.
                Stream stream = BinaryReader.BaseStream;
                long startPosition = stream.Position;
                long bytesAvailable = stream.Length - startPosition;
                if (bytesAvailable < bamlRecord.ContentSize)
                {
                    ThrowException(nameof(SR.ParserDeferContentAsync));
                }
 
                // Read through all the key records and the static resource records
                ArrayList       defKeyList;
                List<object[]>  staticResourceValuesList;
                BaseReadDeferableContentStart(bamlRecord, out defKeyList, out staticResourceValuesList);
 
                // If we don't own the stream, someone might close it when the parse is complete,
                // so copy the defer load contents into a buffer.  If we own the
                // stream, then we'll assume the owner will keep it open.
                long endOfKeysPosition = stream.Position;
                Int32 valuesSize = (Int32)(bamlRecord.ContentSize - endOfKeysPosition + startPosition);
 
                if (!ParserContext.OwnsBamlStream)
                {
                    byte[] buffer = new byte[valuesSize];
 
                    if (valuesSize > 0)
                    {
                        MS.Internal.IO.Packaging.PackagingUtilities.ReliableRead(
                            BinaryReader, buffer, 0, valuesSize);
                    }
 
                    throw new NotImplementedException();
                    //dictionary.SetDeferableContent(buffer,
                    //        ParserContext, _rootElement, defKeyList, staticResourceValuesList);
                }
                else
                {
                    throw new NotImplementedException();
                    //dictionary.SetDeferableContent(_bamlStream,
                    //        endOfKeysPosition, valuesSize,
                    //        ParserContext, _rootElement, defKeyList, staticResourceValuesList);
 
                    //_bamlStream.Seek(valuesSize, SeekOrigin.Current);
                }
            }
        }
 
        internal void BaseReadDeferableContentStart(
            BamlDeferableContentStartRecord bamlRecord,
            out ArrayList                   defKeyList,
            out List<object[]>              staticResourceValuesList)
        {
            // Check for DefAttributeKeys and create a key table, if some are
            // present.  Peek ahead in the stream looking for IBamlDictionaryKey types
            // and just process those without touching anything else.
            // NOTE:  The typical shell theme file is roughly 450 bytes per value, so presize
            //        the arraylist to be optimal for these scenarios.
            defKeyList = new ArrayList(Math.Max (5, (int)(bamlRecord.ContentSize/400)));
            staticResourceValuesList = new List<object[]>(defKeyList.Capacity);
            ArrayList staticResources = new ArrayList();
            BamlRecordType nextType = GetNextRecordType();
            while (nextType == BamlRecordType.DefAttributeKeyString ||
                   nextType == BamlRecordType.DefAttributeKeyType ||
                   nextType == BamlRecordType.KeyElementStart)
            {
                BamlRecord keyRecord = GetNextRecord();
                IBamlDictionaryKey dictionaryKeyRecord = keyRecord as IBamlDictionaryKey;
                if (nextType == BamlRecordType.KeyElementStart)
                {
                    // Read forward until we get a KeyElementEnd, at which point
                    // we should have the key object on the reader stack.  Use
                    // that to set the key object in the Key Element Start record.
                    ReadKeyElementStartRecord((BamlKeyElementStartRecord)keyRecord);
                    defKeyList.Add(keyRecord);
                    BamlRecord nestedBamlRecord;
                    bool moreData = true;
                    while (moreData && null != (nestedBamlRecord = GetNextRecord()))
                    {
                        if (nestedBamlRecord is BamlKeyElementEndRecord)
                        {
                            object keyObject = GetCurrentObjectData();
                            MarkupExtension me = keyObject as MarkupExtension;
                            if (me != null)
                            {
                                keyObject = ProvideValueFromMarkupExtension(me, GetParentObjectData(), null);
                            }
                            dictionaryKeyRecord.KeyObject = keyObject;
                            PopContext();
                            moreData = false;
                        }
                        else
                        {
                            moreData = ReadRecord(nestedBamlRecord);
                        }
                    }
                }
                else
                {
                    BamlDefAttributeKeyStringRecord stringKeyRecord = keyRecord as BamlDefAttributeKeyStringRecord;
                    if (stringKeyRecord != null)
                    {
                        // Get the value string from the string table, and cache it in the
                        // record.
                        stringKeyRecord.Value = MapTable.GetStringFromStringId(
                                                        stringKeyRecord.ValueId);
 
                        dictionaryKeyRecord.KeyObject = XamlTypeMapper.GetDictionaryKey(stringKeyRecord.Value, ParserContext);
                        defKeyList.Add(stringKeyRecord);
                    }
                    else
                    {
                        BamlDefAttributeKeyTypeRecord typeKeyRecord = keyRecord as BamlDefAttributeKeyTypeRecord;
                        if (typeKeyRecord != null)
                        {
                            dictionaryKeyRecord.KeyObject = MapTable.GetTypeFromId(
                                             typeKeyRecord.TypeId);
                            defKeyList.Add(typeKeyRecord);
                        }
                        else
                        {
                            // Enum.ToString(culture) is [Obsolete]
                            #pragma warning disable 0618
 
                            ThrowException(nameof(SR.ParserUnexpInBAML), keyRecord.RecordType.ToString(CultureInfo.CurrentCulture));
 
                            #pragma warning restore 0618
                        }
                    }
                }
 
                // Check for StaticResources belonging to this key and create a table, if present.
                // Peek ahead in the stream looking for StaticResource[Start/End] types
                // and just process those without touching anything else.
 
                nextType = GetNextRecordType();
 
                // If this dictionary is a top level deferred section then
                // its front loaded section contains StaticResourceRecords
 
                if (!ParserContext.InDeferredSection)
                {
                    // Example:
                    //
                    // <ResourceDictionary>
                    //   < ... {StaticResource res1} ... />
                    // </ResourceDictionary>
 
                    while (nextType == BamlRecordType.StaticResourceStart ||
                           nextType == BamlRecordType.OptimizedStaticResource)
                    {
                        BamlRecord srRecord = GetNextRecord();
                        if (nextType == BamlRecordType.StaticResourceStart)
                        {
                            // Read forward until we get a StaticResourceEnd, at which point
                            // we should have the StaticResourceExtension object on the reader stack.
                            BamlStaticResourceStartRecord startRecord = (BamlStaticResourceStartRecord)srRecord;
                            BaseReadElementStartRecord(startRecord);
                            BamlRecord nestedBamlRecord;
                            bool moreData = true;
                            while (moreData && null != (nestedBamlRecord = GetNextRecord()))
                            {
                                if (nestedBamlRecord.RecordType == BamlRecordType.StaticResourceEnd)
                                {
                                    StaticResourceExtension staticResource = (StaticResourceExtension)GetCurrentObjectData();
                                    staticResources.Add(staticResource);
                                    PopContext();
                                    moreData = false;
                                }
                                else
                                {
                                    moreData = ReadRecord(nestedBamlRecord);
                                }
                            }
                        }
                        else
                        {
                            StaticResourceExtension staticResource = (StaticResourceExtension)GetExtensionValue((IOptimizedMarkupExtension)srRecord, null);
                            staticResources.Add(staticResource);
                        }
                        nextType = GetNextRecordType();
                    }
                }
                else
                {
                    // Example:
                    //
                    // <Button>
                    // <Button.Template>
                    // <ControlTemplate>
                    //   <StackPanel ... {StaticResource res1} ... >
                    //   <StackPanel.Resources>
                    //     < ... {StaticResource res2} ... />
                    //   </StackPanel.Resources>
                    //   </StackPanel>
                    // </ControlTemplate>
                    // </Button.Template>
                    // </Button>
 
                    // If this dictionary is nested within another deferred section such as a template
                    // content then its front loaded section will have StaticResourceId records that
                    // index into the pre-fetched values on the template.
 
                    object[] staticResourceValues = ParserContext.StaticResourcesStack[ParserContext.StaticResourcesStack.Count-1];
 
                    while (nextType == BamlRecordType.StaticResourceId)
                    {
                        BamlStaticResourceIdRecord bamlStaticResourceIdRecord = (BamlStaticResourceIdRecord)GetNextRecord();
 
                        // Find the StaticResourceValue for the given Id
                        Debug.Assert(staticResourceValues != null, "Must have a list of StaticResourceValues for lookup");
                        DeferredResourceReference prefetchedValue = (DeferredResourceReference)staticResourceValues[bamlStaticResourceIdRecord.StaticResourceId];
                        staticResources.Add(new StaticResourceHolder(prefetchedValue.Key, prefetchedValue));
 
                        // Peek at next record type
                        nextType = GetNextRecordType();
                    }
                }
 
                // Set the StaticResources collection on the DictionaryKeyRecord
                staticResourceValuesList.Add(staticResources.ToArray());
                staticResources.Clear();
 
                nextType = GetNextRecordType();
            }
        }
 
        /// <summary>
        /// Read the node that stores an Id reference to StaticResource records stored in the
        /// front loaded section within the deferred content section in Baml
        /// </summary>
        protected virtual void ReadStaticResourceIdRecord(
            BamlStaticResourceIdRecord bamlStaticResourceIdRecord)
        {
            // Find the StaticResourceValue for the given Id
            object value = GetStaticResourceFromId(bamlStaticResourceIdRecord.StaticResourceId);
 
            // Push a StaticResourceHolder onto the context. This is to be able to pass the
            // PrefetchedValue through to StaticResourceExtension.ProvideValueInternal.
            PushContext(ReaderFlags.ClrObject | ReaderFlags.NeedToAddToTree, value, null, 0);
 
            // Process the end record
            ReadElementEndRecord(true);
        }
 
        /// <summary>
        /// Read the property node that stores an Id reference to StaticResource records stored in the
        /// front loaded section within the deferred content section in Baml
        /// </summary>
        protected virtual void ReadPropertyWithStaticResourceIdRecord(
            BamlPropertyWithStaticResourceIdRecord bamlPropertyWithStaticResourceIdRecord)
        {
            if (null == CurrentContext ||
                (ReaderFlags.DependencyObject != CurrentContext.ContextType &&
                 ReaderFlags.ClrObject != CurrentContext.ContextType))
            {
                ThrowException(nameof(SR.ParserUnexpInBAML), "Property");
            }
 
            // Define attrbuteId
            short attributeId = bamlPropertyWithStaticResourceIdRecord.AttributeId;
 
            // Identify the target element
            object element = GetCurrentObjectData();
 
            // Identify the property
            WpfPropertyDefinition propertyDefinition = new WpfPropertyDefinition(this, attributeId, element is DependencyObject);
 
            // Find the StaticResourceValue for the given Id
            object value = GetStaticResourceFromId(bamlPropertyWithStaticResourceIdRecord.StaticResourceId);
 
            // Read and set the value provided by the MarkupExtension on the element's property
            BaseReadOptimizedMarkupExtension(element, attributeId, propertyDefinition, value);
        }
 
        /// <summary>
        /// This is a helper method to find the StaticResource value
        /// corresponding to the given StaticResourceId
        /// </summary>
        internal StaticResourceHolder GetStaticResourceFromId(short staticResourceId)
        {
            // Get the value of the property
            object[] staticResourceValues = ParserContext.StaticResourcesStack[ParserContext.StaticResourcesStack.Count-1];
            Debug.Assert(staticResourceValues != null, "Must have a list of StaticResourceValues for lookup");
 
            // Find the StaticResourceValue for the given Id
            DeferredResourceReference prefetchedValue =
                (DeferredResourceReference)staticResourceValues[staticResourceId];
 
            return new StaticResourceHolder(prefetchedValue.Key, prefetchedValue);
        }
 
        // The base baml record reader has no support for literal content.  Subclasses may
        // wish to use this if they store xml blobs in the baml file as text literal content.
        internal virtual void ReadLiteralContentRecord(
            BamlLiteralContentRecord bamlLiteralContentRecord)
        {
            if (CurrentContext != null)
            {
                 object dpOrPi = null;
                 object parent = null;
                 if (CurrentContext.ContentProperty != null)
                 {
                    dpOrPi = CurrentContext.ContentProperty;
                    parent = CurrentContext.ObjectData;
                 }
                 else if (   (CurrentContext.ContextType == ReaderFlags.PropertyComplexClr)
                           || (CurrentContext.ContextType == ReaderFlags.PropertyComplexDP) )
                 {
                    dpOrPi = CurrentContext.ObjectData;
                    parent = ParentContext.ObjectData;
                 }
 
                IXmlSerializable xmlSerializable = null;
                PropertyInfo pi = dpOrPi as PropertyInfo;
                if (pi != null)
                {
                    if (typeof(IXmlSerializable).IsAssignableFrom(pi.PropertyType))
                    {
                        xmlSerializable = pi.GetValue(parent, null) as IXmlSerializable;
                    }
                }
                else
                {
                    DependencyProperty dp = dpOrPi as DependencyProperty;
                    if (dp != null)
                    {
                        if (typeof(IXmlSerializable).IsAssignableFrom(dp.PropertyType))
                        {
                            xmlSerializable = ((DependencyObject)parent).GetValue(dp) as IXmlSerializable;
                        }
                    }
                }
                if (xmlSerializable != null)
                {
                    // REVIEW: keep reader open, some ReadXml impl like XmlDP's will load XML later on different thread
                    // callee is expected to close reader once done
                    FilteredXmlReader reader = new FilteredXmlReader(
                        bamlLiteralContentRecord.Value,
                        XmlNodeType.Element,
                        ParserContext);
                    xmlSerializable.ReadXml(reader);
                    return;
                }
            }
            ThrowException(nameof(SR.ParserUnexpInBAML), "BamlLiteralContent" );
        }
 
        // Read the start of a complex property section.  Determine the property to set
        // with the object that will be constructed from the following records.
        protected virtual void ReadPropertyComplexStartRecord(
            BamlPropertyComplexStartRecord bamlPropertyRecord)
        {
            if (null == CurrentContext ||
                !(ReaderFlags.ClrObject == CurrentContext.ContextType ||
                  ReaderFlags.DependencyObject == CurrentContext.ContextType))
            {
                ThrowException(nameof(SR.ParserUnexpInBAML), "PropertyComplexStart");
            }
 
            short attributeId = bamlPropertyRecord.AttributeId;
 
            WpfPropertyDefinition propertyDefinition = new WpfPropertyDefinition(
                                    this,
                                    attributeId,
                                    ReaderFlags.DependencyObject == CurrentContext.ContextType /*targetIsDependencyObject*/ );
 
            // Try DependencyProperty optimization.
            if (propertyDefinition.DependencyProperty != null)
            {
                // For the case of a DependencyProperty, store the BamlAttributeInfo on the
                // stack, because we may need to know the actual added owner type for the DP
                // to use in error messages.  This is not available in the DP if there
                // are multiple owners.
                PushContext(ReaderFlags.PropertyComplexDP, propertyDefinition.AttributeInfo, propertyDefinition.PropertyType, 0);
            }
            else if (propertyDefinition.PropertyInfo != null)
            {
                // Regular case for clr property
                PushContext(ReaderFlags.PropertyComplexClr, propertyDefinition.PropertyInfo, propertyDefinition.PropertyType, 0);
            }
            else if (propertyDefinition.AttachedPropertySetter != null)
            {
                // Assignable Attached property
                PushContext(ReaderFlags.PropertyComplexClr, propertyDefinition.AttachedPropertySetter, propertyDefinition.PropertyType, 0);
            }
            else if (propertyDefinition.AttachedPropertyGetter != null)
            {
                // Readonly Attached property
                PushContext(ReaderFlags.PropertyComplexClr, propertyDefinition.AttachedPropertyGetter, propertyDefinition.PropertyType, 0);
            }
            else
            {
                ThrowException(nameof(SR.ParserCantGetDPOrPi), GetPropertyNameFromAttributeId(attributeId));
            }
 
            // Set the name of the property into the context
            CurrentContext.ElementNameOrPropertyName = propertyDefinition.Name;
        }
 
        // Reached the end of a complex property.  Not we are not doing validity checking here,
        // since this should have been done when the BAML was created.
        protected virtual void ReadPropertyComplexEndRecord()
        {
            PopContext();
        }
 
        internal DependencyProperty GetCustomDependencyPropertyValue(BamlPropertyCustomRecord bamlPropertyRecord)
        {
            Type declaringType = null;
            return GetCustomDependencyPropertyValue(bamlPropertyRecord, out declaringType);
        }
 
        internal DependencyProperty GetCustomDependencyPropertyValue(BamlPropertyCustomRecord bamlPropertyRecord,
                                                                     out Type declaringType)
        {
            declaringType = null;
            DependencyProperty dp = null;
            short serializerTypeId = bamlPropertyRecord.SerializerTypeId;
 
            Debug.Assert(serializerTypeId == (short)KnownElements.DependencyPropertyConverter);
 
            if (!bamlPropertyRecord.ValueObjectSet)
            {
                // Handle DP property value stored as an attribInfo Id.
                short dpId = BinaryReader.ReadInt16();
                string dpName = null;
                // if ValueId is a TypeId, then get the DP name that is stored next in the record as a string.
                // else the ValueId is a known DP.
                if (bamlPropertyRecord.IsValueTypeId)
                {
                    dpName = BinaryReader.ReadString();
                }
 
                // Resolve the attribInfo of the prop value read into ValueIdValueId,
                // into an actual DP instance to be used as the prop value.
                dp = MapTable.GetDependencyPropertyValueFromId(dpId, dpName, out declaringType);
                if (dp == null)
                {
                    ThrowException(nameof(SR.ParserCannotConvertPropertyValue), "Property", typeof(DependencyProperty).FullName);
                }
 
                bamlPropertyRecord.ValueObject = dp;
                bamlPropertyRecord.ValueObjectSet = true;
            }
            else
            {
                dp = (DependencyProperty)bamlPropertyRecord.ValueObject;
            }
 
            return dp;
        }
 
        internal object GetCustomValue(BamlPropertyCustomRecord bamlPropertyRecord, Type propertyType, string propertyName)
        {
            object valueObject = null;
 
            if (!bamlPropertyRecord.ValueObjectSet)
            {
                Exception innerException = null;
                short sid = bamlPropertyRecord.SerializerTypeId;
 
                try
                {
                    if (sid == (short)KnownElements.DependencyPropertyConverter)
                    {
                        valueObject = GetCustomDependencyPropertyValue(bamlPropertyRecord);
                    }
                    else
                    {
                        valueObject = bamlPropertyRecord.GetCustomValue(BinaryReader, propertyType, sid, this);
                    }
                }
                catch (Exception e)
                {
                    if( CriticalExceptions.IsCriticalException(e) || e is XamlParseException )
                    {
                        throw;
                    }
 
                    innerException = e;
                }
 
                if (!bamlPropertyRecord.ValueObjectSet && !bamlPropertyRecord.IsRawEnumValueSet)
                {
                    string message = SR.Format(SR.ParserCannotConvertPropertyValue, propertyName, propertyType.FullName);
                    ThrowExceptionWithLine(message, innerException);
                }
            }
            else
            {
                valueObject = bamlPropertyRecord.ValueObject;
            }
 
            return valueObject;
        }
 
        // Read a property record that has value information known only to the
        // property's ValidType.
        protected virtual void ReadPropertyCustomRecord(BamlPropertyCustomRecord bamlPropertyRecord)
        {
            if (null == CurrentContext ||
                (ReaderFlags.DependencyObject != CurrentContext.ContextType &&
                 ReaderFlags.ClrObject != CurrentContext.ContextType))
            {
                ThrowException(nameof(SR.ParserUnexpInBAML), "PropertyCustom");
            }
 
            // the value of the property
            object valueObject = null;
 
            // Get the element to set the property on
            object element = GetCurrentObjectData();
 
            // Get the attributeId
            short attributeId = bamlPropertyRecord.AttributeId;
 
            // Identify the property
            WpfPropertyDefinition propertyDefinition = new WpfPropertyDefinition(this, attributeId, element is DependencyObject);
 
            if (!bamlPropertyRecord.ValueObjectSet)
            {
#if !STRESS
                // Get the value of the property that is obtained from the binary data in the record.
                try
                {
#endif
                    valueObject = GetCustomValue(bamlPropertyRecord, propertyDefinition.PropertyType, propertyDefinition.Name);
#if !STRESS
                }
                catch (Exception e)
                {
                    if( CriticalExceptions.IsCriticalException(e) || e is XamlParseException )
                    {
                        throw;
                    }
 
                    string message = SR.Format(SR.ParserCannotConvertPropertyValue, propertyDefinition.Name, propertyDefinition.PropertyType.FullName);
                    ThrowExceptionWithLine(message, e);
                }
#endif
            }
            else
            {
                valueObject = bamlPropertyRecord.ValueObject;
            }
 
            FreezeIfRequired(valueObject);
 
            if (propertyDefinition.DependencyProperty != null)
            {
                Debug.Assert(element is DependencyObject, "Guaranteed by PropertyDefinition constructor");
                SetDependencyValue((DependencyObject)element, propertyDefinition.DependencyProperty, valueObject);
            }
            else if (propertyDefinition.PropertyInfo != null)
            {
                // Regular case for CLR property
                if (propertyDefinition.IsInternal)
                {
                    bool set = XamlTypeMapper.SetInternalPropertyValue(ParserContext,
                                                                       ParserContext.RootElement,
                                                                       propertyDefinition.PropertyInfo,
                                                                       element,
                                                                       valueObject);
                    if (!set)
                    {
                        ThrowException(nameof(SR.ParserCantSetAttribute), "property", propertyDefinition.Name, "set");
                    }
                }
                else
                {
                    propertyDefinition.PropertyInfo.SetValue(element, valueObject,
                        BindingFlags.Default, null,
                        null, TypeConverterHelper.InvariantEnglishUS);
                }
            }
            else if (propertyDefinition.AttachedPropertySetter != null)
            {
                propertyDefinition.AttachedPropertySetter.Invoke(null, new object[] { element, valueObject });
            }
            else
            {
                ThrowException(nameof(SR.ParserCantGetDPOrPi), GetPropertyNameFromAttributeId(attributeId));
            }
        }
 
        // Read a Property record, get the current element off the context stack and convert
        // the string value of the property into a real object.  Then use the element's SetValue
        // method to set the value for this DependencyProperty, or the PropertyInfo's SetValue
        // method if there is no DependencyProperty.
        protected virtual void ReadPropertyRecord(BamlPropertyRecord bamlPropertyRecord)
        {
            if (null == CurrentContext ||
                (ReaderFlags.DependencyObject != CurrentContext.ContextType &&
                 ReaderFlags.ClrObject != CurrentContext.ContextType))
            {
                ThrowException(nameof(SR.ParserUnexpInBAML), "Property");
            }
 
            ReadPropertyRecordBase(bamlPropertyRecord.Value, bamlPropertyRecord.AttributeId, 0);
        }
 
        // Read a Property record, get the current element off the context stack and convert
        // the string value of the property into a real object using the TypeConverter specified
        // in the property record, rather than the Type's converter.
        protected virtual void ReadPropertyConverterRecord(BamlPropertyWithConverterRecord bamlPropertyRecord)
        {
            if (null == CurrentContext ||
                (ReaderFlags.DependencyObject != CurrentContext.ContextType &&
                 ReaderFlags.ClrObject != CurrentContext.ContextType))
            {
                ThrowException(nameof(SR.ParserUnexpInBAML), "Property");
            }
 
            ReadPropertyRecordBase(bamlPropertyRecord.Value, bamlPropertyRecord.AttributeId,
                                   bamlPropertyRecord.ConverterTypeId);
        }
 
        // Read a Property record, get the current element off the context stack and convert
        // the string value of the property into a real object.  Obtain the string value
        // from the string table in the baml file.
        protected virtual void ReadPropertyStringRecord(BamlPropertyStringReferenceRecord bamlPropertyRecord)
        {
            if (null == CurrentContext ||
                (ReaderFlags.DependencyObject != CurrentContext.ContextType &&
                 ReaderFlags.ClrObject != CurrentContext.ContextType))
            {
                ThrowException(nameof(SR.ParserUnexpInBAML), "Property");
            }
 
            string attribValue = GetPropertyValueFromStringId(bamlPropertyRecord.StringId);
            ReadPropertyRecordBase(attribValue, bamlPropertyRecord.AttributeId,
                                   0);
        }
 
        private object GetInnerExtensionValue(IOptimizedMarkupExtension optimizedMarkupExtensionRecord)
        {
            object valueObject = null;
            short memberId = optimizedMarkupExtensionRecord.ValueId;
 
            if (optimizedMarkupExtensionRecord.IsValueTypeExtension)
            {
                valueObject = MapTable.GetTypeFromId(memberId);
            }
            else if (optimizedMarkupExtensionRecord.IsValueStaticExtension)
            {
                valueObject = GetStaticExtensionValue(memberId);
            }
            else
            {
                valueObject = MapTable.GetStringFromStringId(memberId);
            }
 
            return valueObject;
        }
 
        private object GetStaticExtensionValue(short memberId)
        {
            object valueObject = null;
 
            if (memberId < 0)
            {
                short keyId = (short)-memberId;
                
                // if keyId is more than the range it is the actual resource, else it is the key.
 
                bool isKey;
                keyId = SystemResourceKey.GetSystemResourceKeyIdFromBamlId(keyId, out isKey);
 
                if (isKey)
                {
                    valueObject = SystemResourceKey.GetResourceKey(keyId);
                }
                else
                {
                    valueObject = SystemResourceKey.GetResource(keyId);
                }
            }
            else
            {
                BamlAttributeInfoRecord attribInfo = MapTable.GetAttributeInfoFromId(memberId);
                if (attribInfo != null)
                {
                    StaticExtension se = new StaticExtension();
                    se.MemberType = MapTable.GetTypeFromId(attribInfo.OwnerTypeId);
                    se.Member = attribInfo.Name;
                    valueObject = se.ProvideValue(null);
                }
            }
 
            return valueObject;
        }
 
        internal virtual object GetExtensionValue(
            IOptimizedMarkupExtension optimizedMarkupExtensionRecord,
            string                    propertyName)
        {
            object innerExtensionValue = null;
            object valueObject = null;
            short memberId = optimizedMarkupExtensionRecord.ValueId;
            short extensionTypeId = optimizedMarkupExtensionRecord.ExtensionTypeId;
 
            switch (extensionTypeId)
            {
                case (short)KnownElements.StaticExtension:
                    valueObject = GetStaticExtensionValue(memberId);
                    break;
 
                case (short)KnownElements.DynamicResourceExtension:
                    innerExtensionValue = GetInnerExtensionValue(optimizedMarkupExtensionRecord);
                    valueObject = new DynamicResourceExtension(innerExtensionValue);
                    break;
 
                case (short)KnownElements.StaticResourceExtension:
                    innerExtensionValue = GetInnerExtensionValue(optimizedMarkupExtensionRecord);
                    valueObject = new StaticResourceExtension(innerExtensionValue);
                    break;
            }
 
            if (valueObject == null)
            {
                string valueTypeName = string.Empty;
 
                switch (extensionTypeId)
                {
                    case (short)KnownElements.StaticExtension:
                        valueTypeName = typeof(StaticExtension).FullName;
                        break;
                    case (short)KnownElements.DynamicResourceExtension:
                        valueTypeName = typeof(DynamicResourceExtension).FullName;
                        break;
                    case (short)KnownElements.StaticResourceExtension:
                        valueTypeName = typeof(StaticResourceExtension).FullName;
                        break;
                }
 
                ThrowException(nameof(SR.ParserCannotConvertPropertyValue), propertyName, valueTypeName);
            }
 
            return valueObject;
        }
 
        protected virtual void ReadPropertyWithExtensionRecord(BamlPropertyWithExtensionRecord bamlPropertyRecord)
        {
            if (null == CurrentContext ||
                (ReaderFlags.DependencyObject != CurrentContext.ContextType &&
                 ReaderFlags.ClrObject != CurrentContext.ContextType))
            {
                ThrowException(nameof(SR.ParserUnexpInBAML), "Property");
            }
 
            // Define attrbuteId
            short attributeId = bamlPropertyRecord.AttributeId;
 
            // Identify the target element
            object element = GetCurrentObjectData();
 
            // Identify the property
            WpfPropertyDefinition propertyDefinition = new WpfPropertyDefinition(this, attributeId, element is DependencyObject);
 
            // Get the value of the property
            object value = GetExtensionValue(bamlPropertyRecord, propertyDefinition.Name);
 
            // Read and set the value provided by the MarkupExtension on the element's property
            BaseReadOptimizedMarkupExtension(element, attributeId, propertyDefinition, value);
        }
 
        private void BaseReadOptimizedMarkupExtension(
            object             element,
            short              attributeId,
            WpfPropertyDefinition propertyDefinition,
            object             value)
        {
#if !STRESS
            try
            {
#endif
                // if the value is a ME, get the actual value from it.
                MarkupExtension me = value as MarkupExtension;
                if (me != null)
                {
                    value = ProvideValueFromMarkupExtension(me, element, propertyDefinition.DpOrPiOrMi);
 
                    if( TraceMarkup.IsEnabled )
                    {
                        TraceMarkup.TraceActivityItem(
                                              TraceMarkup.ProvideValue,
                                              me,
                                              element,
                                              propertyDefinition.DpOrPiOrMi,
                                              value );
                    }
                }
 
                if( !SetPropertyValue( element, propertyDefinition, value ))
                {
                    ThrowException(nameof(SR.ParserCantGetDPOrPi), GetPropertyNameFromAttributeId(attributeId));
                }
 
#if !STRESS
            }
            catch( Exception e )
            {
                if (CriticalExceptions.IsCriticalException(e) || e is XamlParseException)
                {
                    throw;
                }
 
                TargetInvocationException tie = e as TargetInvocationException;
                if( tie != null )
                {
                    e = tie.InnerException;
                }
 
                string message = SR.Format(SR.ParserCannotConvertPropertyValue, propertyDefinition.Name, propertyDefinition.PropertyType.FullName);
                ThrowExceptionWithLine(message, e);
            }
#endif
        }
 
 
        //
        // Set a value onto a property of an object.  The property could be a DP
        // or a CLR property (figure out from the PropertyDefinition).
        //
 
        private bool SetPropertyValue( Object o, WpfPropertyDefinition propertyDefinition, object value )
        {
            bool succeeded = true;
 
            //
            // DP case
            //
 
            if (propertyDefinition.DependencyProperty != null)
            {
                if( TraceMarkup.IsEnabled )
                {
                    TraceMarkup.Trace( TraceEventType.Start,
                                     TraceMarkup.SetPropertyValue,
                                     o,
                                     propertyDefinition.DependencyProperty.Name,
                                     value);
                }
 
                Debug.Assert(o is DependencyObject);
                SetDependencyValue((DependencyObject)o, propertyDefinition.DependencyProperty, value);
 
                if( TraceMarkup.IsEnabled )
                {
                    TraceMarkup.Trace( TraceEventType.Stop,
                                     TraceMarkup.SetPropertyValue,
                                     o,
                                     propertyDefinition.DependencyProperty.Name,
                                     value);
                }
            }
 
            //
            // Non-attached CLR property case.
            //
 
            else if (propertyDefinition.PropertyInfo != null)
            {
                if( TraceMarkup.IsEnabled )
                {
                    TraceMarkup.Trace( TraceEventType.Start,
                                     TraceMarkup.SetPropertyValue,
                                     o,
                                     propertyDefinition.PropertyInfo.Name,
                                     value);
                }
 
                if (propertyDefinition.IsInternal)
                {
                    bool set = XamlTypeMapper.SetInternalPropertyValue(ParserContext,
                                                                       ParserContext.RootElement,
                                                                       propertyDefinition.PropertyInfo,
                                                                       o,
                                                                       value);
                    if (!set)
                    {
                        ThrowException(nameof(SR.ParserCantSetAttribute), "property", propertyDefinition.Name, "set");
                    }
                }
                else
                {
                    propertyDefinition.PropertyInfo.SetValue(o, value, BindingFlags.Default, null, null, TypeConverterHelper.InvariantEnglishUS);
                }
 
                if( TraceMarkup.IsEnabled )
                {
                    TraceMarkup.Trace( TraceEventType.Stop,
                                     TraceMarkup.SetPropertyValue,
                                     o,
                                     propertyDefinition.PropertyInfo.Name,
                                     value);
                }
            }
 
            //
            // Attached CLR property case
            //
 
            else if (propertyDefinition.AttachedPropertySetter != null)
            {
                if( TraceMarkup.IsEnabled )
                {
                    TraceMarkup.Trace( TraceEventType.Start,
                                     TraceMarkup.SetPropertyValue,
                                     o,
                                     propertyDefinition.AttachedPropertySetter.Name,
                                     value);
                }
 
                propertyDefinition.AttachedPropertySetter.Invoke(null, new object[] { o, value });
 
                if( TraceMarkup.IsEnabled )
                {
                    TraceMarkup.Trace( TraceEventType.Stop,
                                     TraceMarkup.SetPropertyValue,
                                     o,
                                     propertyDefinition.AttachedPropertySetter.Name,
                                     value);
                }
            }
 
            //
            // Error case
            //
 
            else
            {
                succeeded = false;
            }
 
            return succeeded;
        }
 
 
        // Read a Property record, get the current element off the context stack and a Type
        // object from the TypeId in the property record.  This is the object to set
        // on the property.
        protected virtual void ReadPropertyTypeRecord(BamlPropertyTypeReferenceRecord bamlPropertyRecord)
        {
            if (null == CurrentContext ||
                (ReaderFlags.DependencyObject != CurrentContext.ContextType &&
                 ReaderFlags.ClrObject != CurrentContext.ContextType))
            {
                ThrowException(nameof(SR.ParserUnexpInBAML), "Property");
            }
 
            // Define attrbuteId
            short attributeId = bamlPropertyRecord.AttributeId;
 
            // Identify the target element
            object element = GetCurrentObjectData();
 
            // Get value type
            Type valueType = MapTable.GetTypeFromId(bamlPropertyRecord.TypeId);
 
            // Identify the property
            WpfPropertyDefinition propertyDefinition = new WpfPropertyDefinition(this, attributeId, element is DependencyObject);
 
#if !STRESS
            try
            {
#endif
                if( !SetPropertyValue( element, propertyDefinition, valueType ))
                {
                    ThrowException(nameof(SR.ParserCantGetDPOrPi), GetPropertyNameFromAttributeId(attributeId));
                }
#if !STRESS
            }
            catch (Exception e)
            {
                if (CriticalExceptions.IsCriticalException(e) || e is XamlParseException)
                {
                    throw;
                }
 
                TargetInvocationException tie = e as TargetInvocationException;
                if( tie != null )
                {
                    e = tie.InnerException;
                }
 
                ThrowExceptionWithLine(SR.Format(SR.ParserCannotSetValue, element.GetType().FullName, propertyDefinition.Name, valueType.Name), e);
            }
#endif
        }
 
        // Common section for setting a property defined by an attributeId to a value.
        private void ReadPropertyRecordBase(
            string   attribValue,
            short    attributeId,
            short    converterTypeId)
        {
            if( CurrentContext.CreateUsingTypeConverter )
            {
                // TypeConverter syntax rules state that there shall be no specifying
                //  property values on the TypeConverter object specification.
 
                // But like every other rule in XAML, we have an exception.
 
                // Exception: the xml:space property value is tolerated.  We set the
                //  ParserContext information and drop the rest of the data on the
                //  ground.  (We will not set the XmlSpace attached property like
                //  we would for non-TypeConverter-created objects.)
 
#if DEBUG
                // If we ever have more than one exception to the TypeConverter
                //  rule, we'll need to run this differentiation code outside of
                //  debug-only code path, too.
                short ownerTypeId;
                string name;
                BamlAttributeUsage attributeUsage;
                MapTable.GetAttributeInfoFromId(attributeId, out ownerTypeId, out name, out attributeUsage);
 
                Debug.Assert( attributeUsage == BamlAttributeUsage.XmlSpace,
                    "The xml:space attribute is the only one deemed compatible with TypeConverter syntax, but we've encountered something else.  How did this slip by the XamlReaderHelper TypeConverter syntax check?");
#endif
 
                ParserContext.XmlSpace = attribValue;
 
                // ParserContext state updated, and that's all we'll do for this record.
                return;
            }
 
            // If we get this far, it means we are not going to create an object
            //  using its type converter, hence it's safe to call GetCurrentObjectForData().
            //  (GetCurrentObjectData will create an instance using the default constructor,
            //   eliminating the possibility of TypeConverter creation.)
            object element = GetCurrentObjectData();
 
            // Get attributeUsage - using perf optimized call (avoiding attributeInfo record allocation)
            WpfPropertyDefinition propertyDefinition = new WpfPropertyDefinition(this, attributeId, element is DependencyObject);
 
#if !STRESS
            try
            {
#endif
                switch (propertyDefinition.AttributeUsage)
                {
                    case BamlAttributeUsage.RuntimeName:
                        // Add Name to appropriate scope
                        DoRegisterName(attribValue, element);
                        break;
 
                    case BamlAttributeUsage.XmlLang:
                        ParserContext.XmlLang = attribValue;
                        break;
 
                    case BamlAttributeUsage.XmlSpace:
                        ParserContext.XmlSpace = attribValue;
                        break;
                }
 
                // Try DependencyProperty case: If the property is a DP we can handle it faster than the general reflection case
                if (propertyDefinition.DependencyProperty != null)
                {
                    Debug.Assert(element is DependencyObject);
 
                    object propertyValue = ParseProperty(
                        (DependencyObject)element,
                        propertyDefinition.PropertyType,
                        propertyDefinition.Name,
                        propertyDefinition.DependencyProperty,
                        attribValue,
                        converterTypeId);
 
                    // If the value returned is not unset, then perform a DependencyObject.SetValue.  An
                    // UnsetValue can occur if a resource reference is bound or some other way of setting
                    // up the value is done in ParseProperty.
                    if (propertyValue != DependencyProperty.UnsetValue)
                    {
                        SetPropertyValue( element, propertyDefinition, propertyValue );
                    }
                }
                else if (propertyDefinition.PropertyInfo != null)
                {
                    // General case of CLR or Attached property
 
                    // Calculate the value of the property
                    object propertyValue = ParseProperty(
                        element,
                        propertyDefinition.PropertyType,
                        propertyDefinition.Name,
                        propertyDefinition.PropertyInfo,
                        attribValue, converterTypeId);
 
                    // If the value returned is not unset, then perform a PropertyInfo.SetValue.
                    // An UnsetValue can occur if a resource reference is bound or some other
                    // way of setting up the value is done in ParseProperty.
                    if (propertyValue != DependencyProperty.UnsetValue)
                    {
                        // Assign the value to the property
                        SetPropertyValue( element, propertyDefinition, propertyValue );
                    }
                }
                else if (propertyDefinition.AttachedPropertySetter != null)
                {
                    // Attached property
                    // General case of CLR or Attached property
 
                    // Calculate the value of the property
                    object propertyValue = ParseProperty(
                        element,
                        propertyDefinition.PropertyType,
                        propertyDefinition.Name,
                        propertyDefinition.AttachedPropertySetter,
                        attribValue, converterTypeId);
 
                    // If the value returned is not unset, then perform a PropertyInfo.SetValue.
                    // An UnsetValue can occur if a resource reference is bound or some other
                    // way of setting up the value is done in ParseProperty.
                    if (propertyValue != DependencyProperty.UnsetValue)
                    {
                        // Attached Property accessible via SetFoo/GetFoo static methods
                        SetPropertyValue( element, propertyDefinition, propertyValue );
                    }
                }
                else
                {
                    // Neither DP, nor Clr, nor Attached property.
 
                    // We may have found the attribute record (which should always work unless
                    // the file is corrupted), but it may not resolve to a property with the
                    // currently loaded set of assemblies. Try a locally defined event before complaining.
                    bool isRE = false;
                    object reidOrEi = null;
                    bool isInternal = false;
 
                    if (_componentConnector != null && _rootElement != null)
                    {
                        reidOrEi = GetREOrEiFromAttributeId(attributeId, out isInternal, out isRE);
                    }
 
                    if (reidOrEi != null)
                    {
                        Delegate d;
 
                        if (isRE)
                        {
                            RoutedEvent reid = reidOrEi as RoutedEvent;
                            d = XamlTypeMapper.CreateDelegate(ParserContext,
                                                              reid.HandlerType,
                                                              ParserContext.RootElement,
                                                              attribValue);
                            if (d == null)
                            {
                                ThrowException(nameof(SR.ParserCantCreateDelegate), reid.HandlerType.Name, attribValue);
                            }
 
                            UIElement uiel = element as UIElement;
                            if (uiel != null)
                            {
                                uiel.AddHandler(reid, d);
                            }
                            else
                            {
                                ContentElement ce = element as ContentElement;
                                if (ce != null)
                                {
                                    ce.AddHandler(reid, d);
                                }
                                else
                                {
                                    // In the case where the element doesn't support any routed event AddHandler
                                    // we know the null pointer exception is caught and wrapped in a XAML parse exception
                                    // below (we would have added an error message but 3.5 doesn't allow us to add one).
                                    UIElement3D uie3D = element as UIElement3D;
                                    uie3D.AddHandler(reid, d);
                                }
                            }
                        }
                        else
                        {
                            EventInfo ei = reidOrEi as EventInfo;
                            d = XamlTypeMapper.CreateDelegate(ParserContext,
                                                              ei.EventHandlerType,
                                                              ParserContext.RootElement,
                                                              attribValue);
                            if (d == null)
                            {
                                ThrowException(nameof(SR.ParserCantCreateDelegate), ei.EventHandlerType.Name, attribValue);
                            }
 
                            if (isInternal)
                            {
                                bool added = XamlTypeMapper.AddInternalEventHandler(ParserContext,
                                                                                    ParserContext.RootElement,
                                                                                    ei,
                                                                                    element,
                                                                                    d);
                                if (!added)
                                {
                                    ThrowException(nameof(SR.ParserCantSetAttribute), "event", ei.Name, "add");
                                }
                            }
                            else
                            {
                                ei.AddEventHandler(element, d);
                            }
                        }
 
                        return;
                    }
                    else
                    {
                        ThrowException(nameof(SR.ParserCantGetDPOrPi), propertyDefinition.Name);
                    }
                }
#if !STRESS
            }
 
            catch (Exception e)
            {
                if (CriticalExceptions.IsCriticalException(e) || e is XamlParseException)
                {
                    throw;
                }
 
                TargetInvocationException tie = e as TargetInvocationException;
                if( tie != null )
                {
                    e = tie.InnerException;
                }
 
                ThrowExceptionWithLine(SR.Format(SR.ParserCannotSetValue, element.GetType().FullName, propertyDefinition.AttributeInfo.Name, attribValue), e);
            }
#endif
 
        }
 
        //+-----------------------------------------------------------------------------------------------------
        //
        //  DoRegisterName
        //
        //  Register a name against the name scope.
        //
        //+-----------------------------------------------------------------------------------------------------
 
        private void DoRegisterName( string name, object element )
        {
            // Store this name in the context (used by XamlParseException).
            if( CurrentContext != null )
            {
                CurrentContext.ElementNameOrPropertyName = name;
            }
 
 
            if (ParserContext != null && ParserContext.NameScopeStack != null)
            {
                if (0 != ParserContext.NameScopeStack.Count)
                {
                    INameScope nameScopeTop = ParserContext.NameScopeStack.Pop() as INameScope;
                    if ((NameScope.NameScopeFromObject(element) != null) && 0 != ParserContext.NameScopeStack.Count)
                    {
                        // Consider the following scenario
                        // <Window x:Name="myWindow">
                        //     ...
                        //     <Style x:Name="myStyle">
                        //         ...
                        //         <SolidColorBrush x:Name="myBrush">
                        //         </SolidColorBrush>
                        //     </Style>
                        // </Window>
                        //
                        // "myWindow" gets registered with the Window
                        // "myStyle" also gets registered with the Window
                        // "myBrush" gets registered with the Style
                        INameScope nameScopePeek = ParserContext.NameScopeStack.Peek() as INameScope;
                        if (nameScopePeek != null)
                        {
                            nameScopePeek.RegisterName(name, element);
                        }
                    }
                    else
                    {
                        nameScopeTop.RegisterName(name, element);
                    }
                    ParserContext.NameScopeStack.Push(nameScopeTop);
                }
            }
        }
 
        // Read the start of an array property.  Set up the BamlArrayHolder that is needed to
        // hold array contents.
        protected void ReadPropertyArrayStartRecord(BamlPropertyArrayStartRecord bamlPropertyArrayStartRecord)
        {
            short  attributeId = bamlPropertyArrayStartRecord.AttributeId;
            object parent = GetCurrentObjectData();
            BamlCollectionHolder holder = new BamlCollectionHolder(this, parent, attributeId, false /*needDefault*/);
 
            if (!holder.PropertyType.IsArray)
            {
                ThrowException(nameof(SR.ParserNoMatchingArray), GetPropertyNameFromAttributeId(attributeId));
            }
 
            Debug.Assert(!holder.ReadOnly); // this is being checked in XamlReaderHelper, just assert
 
            PushContext(ReaderFlags.PropertyArray | ReaderFlags.CollectionHolder, holder, holder.PropertyType, 0);
 
            // Set the name of the property into the context
            CurrentContext.ElementNameOrPropertyName = holder.AttributeName;
        }
 
        // Read the end of an array.  Convert the array holder that has been accumulating
        // the array contents into a real array and set it on the property.
        protected virtual void ReadPropertyArrayEndRecord()
        {
            BamlCollectionHolder holder = (BamlCollectionHolder)GetCurrentObjectData();
 
            // If we don't have a dictionary yet, then create one now.  This can
            // happen if the Array property is read/write, but does not
            // contain a value and there was no array object under the
            // property.
            if (holder.Collection == null)
            {
                InitPropertyCollection(holder, CurrentContext);
            }
 
            ArrayExtension arrayExt = holder.ArrayExt;
 
            Debug.Assert(arrayExt != null);
 
            holder.Collection = ProvideValueFromMarkupExtension(arrayExt, holder, null);
            holder.SetPropertyValue();
 
            PopContext();
        }
 
        // Start of an IList or IEnumerable property.  Get the IList value from the parent
        // object and store it on the reader stack, so that records encountered under this
        // list can be added to it.
        protected virtual void ReadPropertyIListStartRecord(
            BamlPropertyIListStartRecord bamlPropertyIListStartRecord)
        {
            short attributeId = bamlPropertyIListStartRecord.AttributeId;
            object parent = GetCurrentObjectData();
            BamlCollectionHolder holder = new BamlCollectionHolder(this, parent, attributeId);
            Type expectedType = holder.PropertyType;
 
            // If the property does not implement IList or IAddChild, see if the parent
            // (which is the current object on the top of the stack) implements IAddChild
            // and try that for adding items later on.  First look at defined propertyType
            // obtained from the DP or PropertyInfo.  If that doesn't work, then look at
            // the actual type of object retrieved using GetValue.
            ReaderFlags flags = ReaderFlags.Unknown;
            if (typeof(IList).IsAssignableFrom(expectedType))
            {
                flags = ReaderFlags.PropertyIList;
            }
            else if (BamlRecordManager.TreatAsIAddChild(expectedType))
            {
                flags = ReaderFlags.PropertyIAddChild;
                holder.Collection = holder.DefaultCollection;
                holder.ReadOnly = true;
            }
            else if (typeof(IEnumerable).IsAssignableFrom(expectedType) &&
                     (BamlRecordManager.AsIAddChild(GetCurrentObjectData())) != null)
            {
                flags = ReaderFlags.PropertyIAddChild;
                holder.Collection = CurrentContext.ObjectData;
                holder.ReadOnly = true;
                expectedType = CurrentContext.ObjectData.GetType();
            }
            else
            {
                // if we reached this case, then we had a read-only IEnumerable property
                // under a non-IAddChild element.  Throw an exception
                ThrowException(nameof(SR.ParserReadOnlyProp), holder.PropertyDefinition.Name);
            }
 
            PushContext(flags | ReaderFlags.CollectionHolder, holder, expectedType, 0);
 
            // Set the name of the property into the context
            CurrentContext.ElementNameOrPropertyName = holder.AttributeName;
        }
 
        // End of the IList is reached.  Since this is a read only property, there is nothing
        // to do bug pop the reader stack.
        protected virtual void ReadPropertyIListEndRecord()
        {
            SetCollectionPropertyValue(CurrentContext);
 
            PopContext();
        }
 
        // Start of an IDictionary encountered.  Set up the BamlDictionaryHolder on the reader
        // stack so that items can be added to it.
        protected virtual void ReadPropertyIDictionaryStartRecord(
            BamlPropertyIDictionaryStartRecord bamlPropertyIDictionaryStartRecord)
        {
            short  attributeId = bamlPropertyIDictionaryStartRecord.AttributeId;
            object parent = GetCurrentObjectData();
            BamlCollectionHolder holder = new BamlCollectionHolder(this, parent, attributeId);
 
            PushContext(ReaderFlags.PropertyIDictionary | ReaderFlags.CollectionHolder, holder, holder.PropertyType, 0);
 
            // Set the name of the property into the context
            CurrentContext.ElementNameOrPropertyName = holder.AttributeName;
        }
 
        // If the dictionary does not exist already, then set it.  This is indicated by
        // having a non-null DpOrPi in the BamlDictionaryHolder object on the context stack.
        protected virtual void ReadPropertyIDictionaryEndRecord()
        {
            SetCollectionPropertyValue(CurrentContext);
 
            PopContext();
        }
 
        private void SetCollectionPropertyValue(ReaderContextStackData context)
        {
            BamlCollectionHolder holder = (BamlCollectionHolder)context.ObjectData;
 
            if (holder.Collection == null)
            {
                // If we don't have a collection yet, then create one now.  This can
                // happen if the IDictionary property is read/write, but does not
                // contain a value and there was no IDictionary object under the property
 
                InitPropertyCollection(holder, context);
            }
 
            if (!holder.ReadOnly && holder.Collection != holder.DefaultCollection)
            {
                // If we had the default collection is not the same as the collection in the holder,
                // then either we have a RW property with a null default value or a RW property with an
                // explicit element value.  In either case, set the property's value to be the collection
 
                holder.SetPropertyValue();
            }
        }
 
        // takes a BamlCollectionHolder and its context and sets the value of the holder's collection to be
        // either the default collection instantiated by the holder's constructor or a newly created
        // collection created based on the expected type.
        // *** Used when we do not have an explicit tag.
        private void InitPropertyCollection(BamlCollectionHolder holder, ReaderContextStackData context)
        {
            // this method should only be called to initialize the collection
            Debug.Assert (holder.Collection == null);
 
            if (context.ContextType == ReaderFlags.PropertyArray)
            {
                // arrays are a little different than other collections, because we wrap them in an array extension.
                // Here we create an array extension and assign the element type based on the property.
 
                ArrayExtension arrayExt = new ArrayExtension();
                arrayExt.Type = context.ExpectedType.GetElementType();
                holder.Collection = arrayExt;
            }
            else if (holder.DefaultCollection != null)
            {
                // if we the property getter returned a default value, then we use that collection to insert
                // as the property's collection.
 
                holder.Collection = holder.DefaultCollection;
            }
            else
            {
                ThrowException(nameof(SR.ParserNullPropertyCollection), holder.PropertyDefinition.Name);
            }
 
            context.ExpectedType = null; // Don't want to receive any other values
        }
 
        private BamlCollectionHolder GetCollectionHolderFromContext(ReaderContextStackData context, bool toInsert)
        {
            BamlCollectionHolder holder = (BamlCollectionHolder)context.ObjectData;
 
            // If we don't have a collection yet, then create one now.
            if (holder.Collection == null && toInsert)
            {
                // if this collection holder has not yet been used, then initialize its collection
                InitPropertyCollection(holder, context);
            }
 
            if (toInsert && holder.IsClosed)
            {
                // if an explicit collection was under a collection property and following its end tag an element
                // was placed, then throw an exception.
                ThrowException(nameof(SR.ParserPropertyCollectionClosed), holder.PropertyDefinition.Name);
            }
 
            return holder;
        }
 
        protected IDictionary GetDictionaryFromContext(ReaderContextStackData context, bool toInsert)
        {
            IDictionary result = null;
 
            if (context != null)
            {
                if (context.CheckFlag(ReaderFlags.IDictionary))
                {
                    result = (IDictionary)GetObjectDataFromContext(context);
                }
                else if (context.ContextType == ReaderFlags.PropertyIDictionary)
                {
                    BamlCollectionHolder holder = GetCollectionHolderFromContext(context, toInsert);
 
                    result = holder.Dictionary;
                }
            }
 
            return result;
        }
 
        private IList GetListFromContext(ReaderContextStackData context)
        {
            IList result = null;
 
            if (context != null)
            {
                if (context.CheckFlag(ReaderFlags.IList))
                {
                    result = (IList)GetObjectDataFromContext(context);
                }
                else if (context.ContextType == ReaderFlags.PropertyIList)
                {
                    BamlCollectionHolder holder = GetCollectionHolderFromContext(context, true /*toInsert*/);
 
                    result = holder.List;
                }
            }
 
            return result;
        }
 
        private IAddChild GetIAddChildFromContext(ReaderContextStackData context)
        {
            IAddChild result = null;
 
            if (context != null)
            {
                if (context.CheckFlag(ReaderFlags.IAddChild))
                {
                    result = BamlRecordManager.AsIAddChild(context.ObjectData);
                }
                else if (context.ContextType == ReaderFlags.PropertyIAddChild)
                {
                    BamlCollectionHolder holder = GetCollectionHolderFromContext(context, false /*toInsert*/);
 
                    result = BamlRecordManager.AsIAddChild(holder.Collection);
                }
            }
 
            return result;
        }
 
        private ArrayExtension GetArrayExtensionFromContext(ReaderContextStackData context)
        {
            ArrayExtension result = null;
 
            if (context != null)
            {
                result = context.ObjectData as ArrayExtension;
 
                if (context.CheckFlag(ReaderFlags.ArrayExt))
                {
                    result = (ArrayExtension)context.ObjectData;
                }
                else if (context.ContextType == ReaderFlags.PropertyArray)
                {
                    BamlCollectionHolder holder = GetCollectionHolderFromContext(context, true /*toInsert*/);
 
                    result = holder.ArrayExt;
                }
            }
 
            return result;
        }
 
        // Read a x:foo="bar" record.  If foo is "Name" then this is
        // a dictionary key record which is stored in the BamlDictionaryHolder until the end of
        // the current object is read.  Then it is used as a key to add the current
        // object to the parent dictionary.  This is currently all the reader understands,
        // but a more general handling of def records will occur with PS# 14348
        //
        // Second special case added: If foo is "Uid" then this is an identifier
        //  unique to this tag.  This is added by a MSBuild pre-processing step
        //  or a tool, and is used for localization or accessibility.  In the
        //  case of UIElement objects, this value will end up as an attached
        //  property DefinitionProperties.UidProperty.
        //
        protected virtual void ReadDefAttributeRecord(BamlDefAttributeRecord bamlDefAttributeRecord)
        {
            // Get the name of the attribute from the string table, and cache it in the
            // def record.
            bamlDefAttributeRecord.Name = MapTable.GetStringFromStringId(
                                            bamlDefAttributeRecord.NameId);
 
            if (bamlDefAttributeRecord.Name == XamlReaderHelper.DefinitionName)
            {
                object key = XamlTypeMapper.GetDictionaryKey(bamlDefAttributeRecord.Value, ParserContext);
 
                if (key == null)
                {
                    ThrowException(nameof(SR.ParserNoResource), bamlDefAttributeRecord.Value);
                }
 
                SetKeyOnContext(key, bamlDefAttributeRecord.Value, CurrentContext, ParentContext);
            }
 
            else if(bamlDefAttributeRecord.Name == XamlReaderHelper.DefinitionUid ||
                    bamlDefAttributeRecord.NameId == BamlMapTable.UidStringId)
            {
                // The x:Uid attribute is added to all elements in the markup.
                //  This means we'll be called here under all sorts of conditions,
                //  most of which are meaningless.  Just ignore the useless parts.
 
                // If we don't have an object to set to - bail.
                if( CurrentContext == null )
                    return;
 
                CurrentContext.Uid = bamlDefAttributeRecord.Value;
 
                // UIDs are only meaningful on UIElements.  Ignore all cases where
                //  the attribute was added to irrelevant elements.  Don't instantiate delay
                //  created objects here by calling GetCurrentObjectData(), because delay
                //  created objects are never UIElements. Instantiating non-UIElements here
                //  will cause delay creation of value types to fail.
                UIElement element = CurrentContext.ObjectData as UIElement;
                if( element != null )
                {
                    SetDependencyValue(element, UIElement.UidProperty, bamlDefAttributeRecord.Value);
                }
            }
 
            else if (bamlDefAttributeRecord.Name == XamlReaderHelper.DefinitionShared)
            {
                // The x:Shared token information was stored in the IBamlDictionaryKey
                // in the compiled case. Otherwise, it makes no sense to use it.
                ThrowException(nameof(SR.ParserDefSharedOnlyInCompiled));
            }
 
            else if (bamlDefAttributeRecord.Name == XamlReaderHelper.DefinitionRuntimeName) // x:Name
            {
                object element = GetCurrentObjectData();
 
                if( element != null )
                {
                    DoRegisterName(bamlDefAttributeRecord.Value, element);
                }
            }
            else
            {
                // You will only get this error if the XamlParser is out of sync
                // with the BamlRecordReader (since it should catch unknown def
                // attributes), or if a BamlWriter was used to write
                // a bogus attribute.
                ThrowException(nameof(SR.ParserUnknownDefAttribute), bamlDefAttributeRecord.Name);
            }
        }
 
 
 
        // Read a x:Key="{x:Type Foo}" record.  If foo has been resolved at compile or parse
        // time into a type represented by a TypeId in the baml record.  This is done for
        // more efficient key assignments in a dictionary.
        //
        protected virtual void ReadDefAttributeKeyTypeRecord(
            BamlDefAttributeKeyTypeRecord bamlDefAttributeRecord)
        {
            // Get the actual type from the TypeId
            Type keyType = MapTable.GetTypeFromId(bamlDefAttributeRecord.TypeId);
 
            if (keyType == null)
            {
                ThrowException(nameof(SR.ParserNoResource), XamlReaderHelper.DefinitionName);
            }
 
            SetKeyOnContext(keyType, XamlReaderHelper.DefinitionName, CurrentContext, ParentContext);
        }
 
 
        // Sets the "key" arg as the key on "context".  "parentContext" is the context
        // one level above "context".  Verification is done to make sure that the
        // "parentContext" is a valid Dictionary.  An error is thrown if it is not.
        private void SetKeyOnContext(
            object key,
            string attributeName,
            ReaderContextStackData context,
            ReaderContextStackData parentContext)
        {
            try
            {
                // make sure parent is a dictionary
                GetDictionaryFromContext(parentContext, true /*toInsert*/);
            }
            catch (XamlParseException e)
            {
                // rethrow with a better error message
                if (parentContext.CheckFlag(ReaderFlags.CollectionHolder))
                {
                    BamlCollectionHolder holder = (BamlCollectionHolder)parentContext.ObjectData;
                    object element = context.ObjectData;
 
                    if (element != null && element == holder.Dictionary)
                    {
                        ThrowExceptionWithLine(SR.Format(SR.ParserKeyOnExplicitDictionary, attributeName,
                                       element.GetType().ToString(), holder.PropertyDefinition.Name), e);
                    }
                }
 
                ThrowExceptionWithLine(SR.Format(SR.ParserNoMatchingIDictionary, attributeName), e);
            }
 
            // set key on context
            context.Key = key;
        }
 
 
        // Text content has been read.  This may be a text child of an object or
        // it may be the value of a complex property, or it may the only content
        // in the stream (in which case we just have Text as the root...)
        protected virtual void ReadTextRecord(BamlTextRecord bamlTextRecord)
        {
            BamlTextWithIdRecord bamlTextWithId = bamlTextRecord as BamlTextWithIdRecord;
            if (bamlTextWithId != null)
            {
                // Get the value string from the string table, and cache it in the
                // record.
                bamlTextWithId.Value = MapTable.GetStringFromStringId(
                                                bamlTextWithId.ValueId);
            }
 
            if (null == CurrentContext)
            {
                // It is okay to have a null context and we are doing a fragment
                // and this is a top-level item. If the context is null
                // just add the text to the RootList Array.
 
                // set the _componentConnector and Element properties to NULL.
                _componentConnector = null;
                _rootElement = null;
 
                // Add raw text to the root list.
                RootList.Add(bamlTextRecord.Value);
 
                return;
            }
 
            // Creating a type form text involves a type converter.
            // Check if there is a type converter associated with this text.
            short converterTypeId = 0; // 0 is an invalid typeId for a converter
            BamlTextWithConverterRecord bamlTextWithConverter = bamlTextRecord as BamlTextWithConverterRecord;
            if (bamlTextWithConverter != null)
            {
                converterTypeId = bamlTextWithConverter.ConverterTypeId;
            }
 
            switch (CurrentContext.ContextType)
            {
                // Typical case of text content under an object
                case ReaderFlags.DependencyObject:
                case ReaderFlags.ClrObject:
                {
                    if (CurrentContext.CreateUsingTypeConverter)
                    {
                        Debug.Assert( CurrentContext.ObjectData == null && CurrentContext.ExpectedType != null,
                            "We had expected to create this object using a TypeConverter - but there's already an instance here.  Who created the instance and broke our ability to use a TypeConverter?");
 
                        // Use a TypeConverter to create an object instance from text.
                        object o = GetObjectFromString(CurrentContext.ExpectedType, bamlTextRecord.Value, converterTypeId);
                        if (DependencyProperty.UnsetValue != o)
                        {
                            CurrentContext.ObjectData = o;
                            CurrentContext.ExpectedType = null;
                        }
                        else
                        {
                            ThrowException(nameof(SR.ParserCannotConvertString), bamlTextRecord.Value,
                                           CurrentContext.ExpectedType.FullName);
                        }
                    }
                    else
                    {
                        // Should not use a TypeConverter - the text is to be
                        //  treated as content of object.  GetCurrentObjectData will
                        //  create an instance if one doesn't already exist.
                        object parent = GetCurrentObjectData();
                        if (parent == null)
                        {
                            // GetCurrentObjectData failed to create an object for us to add content to.
                            ThrowException(nameof(SR.ParserCantCreateInstanceType), CurrentContext.ExpectedType.FullName);
                        }
 
                        // We have object instance, and we have several ways to put
                        //  text into that object.
                        IAddChild iacParent = GetIAddChildFromContext(CurrentContext);
                        if (iacParent != null)
                        {
                            iacParent.AddText(bamlTextRecord.Value);
                        }
                        else if (CurrentContext.ContentProperty != null)
                        {
                            AddToContentProperty(parent, CurrentContext.ContentProperty, bamlTextRecord.Value);
                        }
                        else
                        {
                            // All of the above attempts to deal with the text has failed.
                            ThrowException(nameof(SR.ParserIAddChildText),
                                    parent.GetType().FullName,
                                    bamlTextRecord.Value);
                        }
                    }
 
                    break;
                }
 
                case ReaderFlags.PropertyComplexDP:
                {
                    if (null == CurrentContext.ExpectedType)
                    {
                        ThrowException(nameof(SR.ParserNoComplexMulti),
                                       GetPropNameFrom(CurrentContext.ObjectData));
                    }
 
                    // If we get here, the complex property tag's first child is a text element.
                    // The only way text is legal as the child of a complex property is if there are no
                    // other tags under the property, so we assume this is the case and try to convert
                    // from text. If we're wrong, the next tag will throw an error.
                    BamlAttributeInfoRecord attribInfo = CurrentContext.ObjectData as BamlAttributeInfoRecord;
                    object o = ParseProperty(
                                        (DependencyObject)GetParentObjectData(),
                                        attribInfo.DP.PropertyType,
                                        attribInfo.DP.Name,
                                        attribInfo.DP,
                                        bamlTextRecord.Value, converterTypeId);
 
                    if (DependencyProperty.UnsetValue != o)
                    {
                        SetDependencyComplexProperty(o);
                    }
                    else
                    {
                        ThrowException(nameof(SR.ParserCantCreateTextComplexProp),
                              attribInfo.OwnerType.FullName,
                              bamlTextRecord.Value);
                    }
                    break;
                }
 
                case ReaderFlags.PropertyComplexClr:
                {
                    if (null == CurrentContext.ExpectedType)
                    {
                        ThrowException(nameof(SR.ParserNoComplexMulti),
                                       GetPropNameFrom(CurrentContext.ObjectData));
                    }
 
                    // Following same logic as above...
                    object o = GetObjectFromString(CurrentContext.ExpectedType, bamlTextRecord.Value, converterTypeId);
 
                    if (DependencyProperty.UnsetValue != o)
                    {
                        SetClrComplexProperty(o);
                    }
                    else
                    {
                        ThrowException(nameof(SR.ParserCantCreateTextComplexProp),
                            CurrentContext.ExpectedType.FullName, bamlTextRecord.Value);
                    }
 
                    break;
                }
 
                case ReaderFlags.PropertyIAddChild:
                {
                    BamlCollectionHolder holder = GetCollectionHolderFromContext(CurrentContext, true);
                    IAddChild iaddchild = BamlRecordManager.AsIAddChild(holder.Collection);
 
                    if (iaddchild == null)
                    {
                        ThrowException(nameof(SR.ParserNoMatchingIList), "?");
                    }
 
                    iaddchild.AddText(bamlTextRecord.Value);
                    break;
                }
 
                case ReaderFlags.PropertyIList:
                {
                    BamlCollectionHolder holder = GetCollectionHolderFromContext(CurrentContext, true);
 
                    if (holder.List == null)
                    {
                        ThrowException(nameof(SR.ParserNoMatchingIList), "?");
                    }
 
                    holder.List.Add(bamlTextRecord.Value);
                    break;
                }
 
                case ReaderFlags.ConstructorParams:
                {
                    // Store the text parameter in the list of constructor
                    // parameters.  This will be resolved later into the correct
                    // object type once we determine which constructor to use.
                    SetConstructorParameter(bamlTextRecord.Value);
                    break;
                }
 
                default:
                {
                    ThrowException(nameof(SR.ParserUnexpInBAML), "Text");
                    break;
                }
            }
        }
 
        // Read a PresentationOptions:foo="bar" record.
        protected virtual void ReadPresentationOptionsAttributeRecord(BamlPresentationOptionsAttributeRecord bamlPresentationOptionsAttributeRecord)
        {
            // Get the name of the attribute from the string table, and cache it in the
            // def record.
            bamlPresentationOptionsAttributeRecord.Name = MapTable.GetStringFromStringId(
                                            bamlPresentationOptionsAttributeRecord.NameId);
 
            if (bamlPresentationOptionsAttributeRecord.Name == XamlReaderHelper.PresentationOptionsFreeze)
            {
                // Handle PresentationOptions:Freeze attribute by setting
                // a flag in the ParserContext.  When Freezables are added
                // to the tree, they check this flag, and Freeze if required.
                bool freeze = Boolean.Parse(bamlPresentationOptionsAttributeRecord.Value);
 
                _parserContext.FreezeFreezables = freeze;
            }
            else
            {
                // You will only get this error if the XamlParser is out of sync
                // with the BamlRecordReader (since it should catch unknown def
                // attributes), or if a BamlWriter was used to write
                // a bogus attribute.
                ThrowException(nameof(SR.ParserUnknownPresentationOptionsAttribute), bamlPresentationOptionsAttributeRecord.Name);
            }
        }
 
        //
        // Set a property value that will go onto a DP.  Assume that the object to receive the
        // value, and the property on which to set it, are on the reader stack.
        //
        private void SetDependencyComplexProperty(object o)
        {
            Debug.Assert(null != CurrentContext &&
                ReaderFlags.PropertyComplexDP == CurrentContext.ContextType &&
                null != CurrentContext.ExpectedType && null != ParentContext);
 
            object parent = GetParentObjectData();
            BamlAttributeInfoRecord attribInfo = (BamlAttributeInfoRecord)GetCurrentObjectData();
 
            SetDependencyComplexProperty( parent, attribInfo, o );
        }
 
        //
        // Set a property value that will go onto a DP
        //
        private void SetDependencyComplexProperty(
                                object currentTarget,
                                BamlAttributeInfoRecord attribInfo,
                                object o)
        {
            DependencyProperty dp = currentTarget is DependencyObject ? attribInfo.DP : null;
            PropertyInfo propertyInfo = attribInfo.PropInfo;
            MethodInfo attachedPropertySetter = null; // postpone allocating a reflection data until necessary
 
#if !STRESS
            try
            {
#endif
                // ObjectData is either a DependencyProperty or a PropertyInfo.
                // Check if the object is a MarkupExtension.  If so, then get the value
                // to set on this property from the MarkupExtension itself.
                MarkupExtension me = o as MarkupExtension;
                if (me != null)
                {
                    o = ProvideValueFromMarkupExtension(me, currentTarget, dp);
                }
 
                // Check if we have a Nullable type.  If so and the object being set is
                // not a Nullable or an expression, then attempt a conversion.
                Type propertyType = null;
                if (dp != null)
                {
                    propertyType = dp.PropertyType;
                }
                else if (propertyInfo != null)
                {
                    propertyType = propertyInfo.PropertyType;
                }
                else
                {
                    // Touching reflection information about the setter only now to avoid extra memory allocations
                    if (attribInfo.AttachedPropertySetter == null)
                    {
                        XamlTypeMapper.UpdateAttachedPropertySetter(attribInfo);
                    }
                    attachedPropertySetter = attribInfo.AttachedPropertySetter;
                    if (attachedPropertySetter != null)
                    {
                        propertyType = attachedPropertySetter.GetParameters()[1].ParameterType;
                    }
                    else
                    {
                        Debug.Assert(false); 
                    }
                }
                o = OptionallyMakeNullable(propertyType, o, attribInfo.Name);
 
                // DependencyProperty, use the associated DependencyObject's SetValue.  Otherwise
                // use the PropertyInfo's SetValue.
                if (dp != null)
                {
                    Debug.Assert(currentTarget is DependencyObject);
                    SetDependencyValue((DependencyObject)currentTarget, dp, o);
                }
                else if (propertyInfo != null)
                {
                    propertyInfo.SetValue(currentTarget,o,BindingFlags.Default,null,null,
                                    TypeConverterHelper.InvariantEnglishUS);
                }
                else if (attachedPropertySetter != null)
                {
                    attachedPropertySetter.Invoke(null, new object[] { currentTarget, o });
                }
                else
                {
                    Debug.Assert(false); // We do not expect to be here after all checks done in propertyType identification above
                }
 
#if !STRESS
            }
 
            catch (Exception e)
            {
                if (CriticalExceptions.IsCriticalException(e) || e is XamlParseException)
                {
                    throw;
                }
 
                TargetInvocationException tie = e as TargetInvocationException;
                if( tie != null )
                {
                    e = tie.InnerException;
                }
 
                ThrowExceptionWithLine(SR.Format(SR.ParserCannotSetValue, currentTarget.GetType().FullName, attribInfo.Name, o), e);
            }
#endif
 
            // The property has been set, so we do not expect any more child tags --
            // anything more under this context will cause an error
            CurrentContext.ExpectedType = null;
        }
 
        static private Type NullableType = typeof(Nullable<>);
 
        static internal bool IsNullable(Type t)
        {
            return t.IsGenericType && t.GetGenericTypeDefinition() == NullableType;
        }
 
        // If the property being set is nullable and the object is not null or an expression,
        // check if the passed object is the right type.
        internal object OptionallyMakeNullable(Type propertyType, object o, string propName)
        {
            object toReturn = o;
            if( !TryOptionallyMakeNullable( propertyType, propName, ref toReturn ))
            {
                ThrowException(nameof(SR.ParserBadNullableType),
                               propName,
                               ((Type)propertyType.GetGenericArguments()[0]).Name,
                               o.GetType().FullName);
            }
 
            return toReturn;
        }
 
 
        // This is a form of OptionallyMakeNullable that doesn't throw.  We split it out so that the different callers
        // can throw their own exception (StyleHelper uses this too).
 
        static internal bool TryOptionallyMakeNullable( Type propertyType, string propName, ref object o  )
        {
            // if o was nullable, it has been unwrapped and boxed when it was passed into this function
 
            if ((o != null) && IsNullable(propertyType) && !(o is Expression) && !(o is MarkupExtension) )
            {
                Type genericType = (Type)propertyType.GetGenericArguments()[0];
                Debug.Assert(genericType != null);
 
                if (genericType != o.GetType())
                {
                    return false;
                }
            }
 
            return true;
        }
 
 
        //+--------------------------------------------------------------------------------------------------------------------------
        //
        //  SetClrComplexPropertyCore
        //
        //  This virtual is called to set a non-DP property on an object.  The base implementation  sets it via
        //  a property info, but subclasses can override it to avoid reflection.
        //
        //+--------------------------------------------------------------------------------------------------------------------------
 
        internal virtual void SetClrComplexPropertyCore(object parentObject, object value, MemberInfo memberInfo)
        {
            // Check if the object is a MarkupExtension.  If so, then get the value
            // to set on this property from the MarkupExtension itself.
 
            MarkupExtension me = value as MarkupExtension;
            if (me != null)
            {
                value = ProvideValueFromMarkupExtension(me, parentObject, memberInfo);
            }
 
            // Check if we have a Nullable type.  If so and the object being set is
            // not a Nullable or an expression, then attempt a conversion.
            if (memberInfo is PropertyInfo)
            {
                PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
                value = OptionallyMakeNullable(propertyInfo.PropertyType, value, propertyInfo.Name);
 
                propertyInfo.SetValue(parentObject, value, BindingFlags.Default, null, null
                                , TypeConverterHelper.InvariantEnglishUS);
            }
            else
            {
                Debug.Assert(memberInfo is MethodInfo);
                MethodInfo methodInfo = (MethodInfo)memberInfo;
                value = OptionallyMakeNullable(methodInfo.GetParameters()[1].ParameterType, value, methodInfo.Name.Substring("Set".Length));
 
                methodInfo.Invoke(null, new object[] { parentObject, value });
            }
        }
 
 
 
        //
        // Set a property value that will go onto a CLR property (not a DP).  Assume that the object to receive the
        // value, and the property on which to set it, are on the reader stack.
        //
        private void SetClrComplexProperty(object o)
        {
            Debug.Assert(null != CurrentContext &&
                ReaderFlags.PropertyComplexClr == CurrentContext.ContextType &&
                null != CurrentContext.ExpectedType);
 
            MemberInfo memberInfo = (MemberInfo)GetCurrentObjectData();
            object parentObject = GetParentObjectData();
 
            SetClrComplexProperty( parentObject, memberInfo, o );
        }
 
 
        //
        // Set a property value that will go onto a CLR property (not a DP).
        //
        private void SetClrComplexProperty(object parentObject, MemberInfo memberInfo, object o)
        {
#if !STRESS
            try
            {
#endif
                SetClrComplexPropertyCore(parentObject, o, memberInfo);
#if !STRESS
            }
            catch (Exception e)
            {
                if (CriticalExceptions.IsCriticalException(e) || e is XamlParseException)
                {
                    throw;
                }
 
                TargetInvocationException tie = e as TargetInvocationException;
                if( tie != null )
                {
                    e = tie.InnerException;
                }
 
                ThrowExceptionWithLine(SR.Format(SR.ParserCannotSetValue, parentObject.GetType().FullName, memberInfo.Name, o), e);
            }
#endif
 
            // The property has been set, so we do not expect any more child tags --
            // anything more under this context will cause an error
            CurrentContext.ExpectedType = null;
        }
 
        // Called when we are in the context of a constructor and an object end record is
        // encounted.  Add the newly created object to the parameter list.
        void SetConstructorParameter(object o)
        {
            Debug.Assert(null != CurrentContext &&
                ReaderFlags.ConstructorParams == CurrentContext.ContextType);
 
            // The object may be a MarkupExtension, so get its value if that's the case
            // and use that as the element.
            MarkupExtension me = o as MarkupExtension;
            if (me != null)
            {
                o = ProvideValueFromMarkupExtension(me, null, null);
            }
 
            if (CurrentContext.ObjectData == null)
            {
                CurrentContext.ObjectData = o;
                CurrentContext.SetFlag(ReaderFlags.SingletonConstructorParam);
            }
            else if (CurrentContext.CheckFlag(ReaderFlags.SingletonConstructorParam))
            {
                ArrayList paramList = new ArrayList(2);
                paramList.Add(CurrentContext.ObjectData);
                paramList.Add(o);
                CurrentContext.ObjectData = paramList;
                CurrentContext.ClearFlag(ReaderFlags.SingletonConstructorParam);
            }
            else
            {
                ArrayList paramList = (ArrayList) CurrentContext.ObjectData;
                paramList.Add(o);
            }
        }
 
        // Add an XML namespace dictionary entry to the current object in the
        // context stack.
        // NOTE:  Setting Xmlns information on a delay created type is not currently
        //        supported.  The type must have already been instantiated in order to
        //        set the dictionary property on it.  
        protected void SetXmlnsOnCurrentObject(BamlXmlnsPropertyRecord xmlnsRecord)
        {
            DependencyObject e = CurrentContext.ObjectData as DependencyObject;
 
            // For cases where we have object factories, we may not have a valid DependencyObject at
            // this point, so don't try to set the xmlns dictionary.
            if (e != null)
            {
                XmlnsDictionary elemDict = XmlAttributeProperties.GetXmlnsDictionary(e);
 
                if (null != elemDict)
                {
                    elemDict.Unseal();
                    elemDict[xmlnsRecord.Prefix] = xmlnsRecord.XmlNamespace;
                    elemDict.Seal();
                }
                else
                {
                    elemDict = new XmlnsDictionary();
                    elemDict[xmlnsRecord.Prefix] = xmlnsRecord.XmlNamespace;
                    elemDict.Seal();
                    XmlAttributeProperties.SetXmlnsDictionary(e, elemDict);
                }
            }
        }
 
        // Get a property value object given the property's type, name and value string.
        // Throw an exception of the property could not be resolved.
        internal object ParseProperty(
            object    element,
            Type      propertyType,
            string    propertyName,
            object    dpOrPi,
            string    attribValue,
            short     converterTypeId)
        {
            Object propValue = null;
#if !STRESS
            try
            {
#endif
                propValue = XamlTypeMapper.ParseProperty(element, propertyType, propertyName, dpOrPi,
                                                 TypeConvertContext, ParserContext,
                                                 attribValue, converterTypeId);
 
                FreezeIfRequired(propValue);
#if !STRESS
            }
            catch (Exception e)
            {
                if( CriticalExceptions.IsCriticalException(e) || e is XamlParseException )
                {
                    throw;
                }
 
                ThrowPropertyParseError(e, propertyName, attribValue, element, propertyType);
            }
#endif
 
            if (DependencyProperty.UnsetValue == propValue)
            {
                ThrowException(nameof(SR.ParserNullReturned), propertyName, attribValue);
            }
 
            return propValue;
        }
 
        private void ThrowPropertyParseError(
            Exception  e,
            string     propertyName,
            string     attribValue,
            object     element,
            Type       propertyType)
 
        {
            // Property parses can fail if the user mistakenly specified a resource key
            // directly instead of a StaticResource extension.  Check to see if the
            // attribute value is a resource key.
            string message = string.Empty;
            if (FindResourceInParserStack(attribValue.Trim(), false /*allowDeferredResourceReference*/, false /*mustReturnDeferredResourceReference*/) == DependencyProperty.UnsetValue)
            {
                if (propertyType == typeof(Type))
                {
                    message = SR.Format(SR.ParserErrorParsingAttribType,
                                     propertyName, attribValue);
                }
                else
                {
                    message = SR.Format(SR.ParserErrorParsingAttrib,
                                     propertyName, attribValue, propertyType.Name);
                }
            }
            else
            {
                message = SR.Format(SR.ParserErrorParsingAttribType,
                                 propertyName, attribValue);
            }
 
 
            ThrowExceptionWithLine( message, e );
        }
 
        // Name is self-explanatory -- this is used to create CLR objects and such that aren't
        // underneath Elements (those are handled by ParseProperty above).
        object GetObjectFromString(Type type, string s, short converterTypeId)
        {
            object o = DependencyProperty.UnsetValue;
            o = ParserContext.XamlTypeMapper.ParseProperty(null, type,string.Empty, null,
                                       TypeConvertContext,ParserContext,s, converterTypeId);
            return o;
        }
 
        private static object Lookup(
            IDictionary     dictionary,
            object          key,
            bool            allowDeferredResourceReference,
            bool            mustReturnDeferredResourceReference)
        {
            ResourceDictionary resourceDictionary;
            if (allowDeferredResourceReference && (resourceDictionary = dictionary as ResourceDictionary) != null)
            {
                // Attempt to delay load resources from ResourceDictionaries
                bool canCache;
                return resourceDictionary.FetchResource(key, allowDeferredResourceReference, mustReturnDeferredResourceReference, out canCache);
            }
            else
            {
                if (!mustReturnDeferredResourceReference)
                {
                    return dictionary[key];
                }
                else
                {
                    return new DeferredResourceReferenceHolder(key, dictionary[key]);
                }
            }
        }
 
        // Given a key, find object in the parser stack that may hold a
        // ResourceDictionary and search for an object keyed by that key.
        internal object FindResourceInParserStack(
            object  resourceNameObject,
            bool    allowDeferredResourceReference,
            bool    mustReturnDeferredResourceReference)
        {
            object value = DependencyProperty.UnsetValue;
 
            // Walk up the parser stack, looking for DictionaryHolders and DependencyObjects.
            // Check each one for the resource we are searching for until we reach a DependencyObject
            // which is actually in the element tree.  Stop at this one.
 
            ParserStack contextStack = ReaderContextStack;
            BamlRecordReader reader = this;
 
            while( contextStack != null )
            {
                for (int i = contextStack.Count-1; i >= 0; i--)
                {
                    ReaderContextStackData stackData = (ReaderContextStackData) contextStack[i];
                    IDictionary dictionary = GetDictionaryFromContext(stackData, false /*toInsert*/);
 
                    if (dictionary != null && dictionary.Contains(resourceNameObject))
                    {
                        value = Lookup(dictionary, resourceNameObject, allowDeferredResourceReference, mustReturnDeferredResourceReference);
                    }
                    else if (stackData.ContextType == ReaderFlags.DependencyObject)
                    {
                        DependencyObject feOrfceParent = (DependencyObject)stackData.ObjectData;
                        FrameworkElement feParent;
                        FrameworkContentElement fceParent;
 
                        Helper.DowncastToFEorFCE(feOrfceParent, out feParent, out fceParent, false /*throwIfNeither*/);
                        if (feParent != null)
                        {
                            value = feParent.FindResourceOnSelf(resourceNameObject, allowDeferredResourceReference, mustReturnDeferredResourceReference);
                        }
                        else if (fceParent != null)
                        {
                            value = fceParent.FindResourceOnSelf(resourceNameObject, allowDeferredResourceReference, mustReturnDeferredResourceReference);
                        }
                    }
                    else if (stackData.CheckFlag(ReaderFlags.StyleObject))
                    {
                        Style style = (Style)stackData.ObjectData;
 
                        value = style.FindResource(resourceNameObject, allowDeferredResourceReference, mustReturnDeferredResourceReference);
                    }
                    else if (stackData.CheckFlag(ReaderFlags.FrameworkTemplateObject))
                    {
                        FrameworkTemplate frameworkTemplate = (FrameworkTemplate)stackData.ObjectData;
 
                        value = frameworkTemplate.FindResource(resourceNameObject, allowDeferredResourceReference, mustReturnDeferredResourceReference);
                    }
 
                    if (value != DependencyProperty.UnsetValue)
                    {
                        return value;
                    }
                }
 
 
                // If we reach the end of this reader's context stack, see if we should
                // look at another one.
 
                bool newContextStackFound = false;
                while (reader._previousBamlRecordReader != null)
                {
                    // Yes, move to the next reader
                    reader = reader._previousBamlRecordReader;
 
                    if (reader.ReaderContextStack != contextStack)
                    {
                        contextStack = reader.ReaderContextStack;
                        newContextStackFound = true;
                        break;
                    }
                }
 
                if( !newContextStackFound )
                {
                    // Terminate the loop
                    contextStack = null;
                }
            }
 
            return DependencyProperty.UnsetValue;
        }
 
        /// <summary>
        /// Helper function for loading a Resources from RootElement/AppResources/SystemResources.
        /// The passed in object must be a trimmed string or a type.
        /// </summary>
        /// <returns>
        ///  The resource value, if found.  Otherwise DependencyProperty.UnsetValue.
        /// </returns>
        private object FindResourceInRootOrAppOrTheme(
            object  resourceNameObject,
            bool    allowDeferredResourceReference,
            bool    mustReturnDeferredResourceReference)
        {
            // This method should not exist since resource references should be references
            // and not looked up at this point.
            // That not being the case, we need to look at SystemResources and App Resources
            // even when we don't have a reference to an element or tree.
            // System resources lucked out, though...
            object result;
            if (!SystemResources.IsSystemResourcesParsing)
            {
                object source;
                result = FrameworkElement.FindResourceFromAppOrSystem(resourceNameObject, out source, false /*throwOnError*/, allowDeferredResourceReference, mustReturnDeferredResourceReference);
            }
            else
            {
                result = SystemResources.FindResourceInternal(resourceNameObject, allowDeferredResourceReference, mustReturnDeferredResourceReference);
            }
 
            if (result != null)
            {
                return result;
            }
 
            return DependencyProperty.UnsetValue;
        }
 
        // Given a key, find object in the parser stack that may hold a
        // ResourceDictionary and search for an object keyed by that key.
        internal object FindResourceInParentChain(
            object  resourceNameObject,
            bool    allowDeferredResourceReference,
            bool    mustReturnDeferredResourceReference)
        {
            // Try the parser stack first.
            object resource = FindResourceInParserStack(resourceNameObject, allowDeferredResourceReference, mustReturnDeferredResourceReference);
 
            if (resource == DependencyProperty.UnsetValue)
            {
                // If we get to here, we've either walked off the top of the reader stack, or haven't
                // found a value on an element that is in the tree.  In that case, give the RootElement
                // and the parent held in the parser context one last try.  This would occur if the
                // parser is used for literal content that did not contain a DependencyObject tree.
                resource = FindResourceInRootOrAppOrTheme(resourceNameObject, allowDeferredResourceReference, mustReturnDeferredResourceReference);
            }
 
            if (resource == DependencyProperty.UnsetValue && mustReturnDeferredResourceReference)
            {
                resource = new DeferredResourceReferenceHolder(resourceNameObject, DependencyProperty.UnsetValue);
            }
 
            return resource;
        }
 
        // Given a string key, find objects in the parser stack that may hold a
        // ResourceDictionary and call the XamlTypeMapper to try and resolve the key using
        // those objects.
        internal object LoadResource(string resourceNameString)
        {
            string  resourceName = resourceNameString.Substring(1, resourceNameString.Length-2);
            object  resourceNameObject = XamlTypeMapper.GetDictionaryKey(resourceName, ParserContext);
            if (resourceNameObject == null)
            {
               ThrowException(nameof(SR.ParserNoResource), resourceNameString);
            }
 
            object value = FindResourceInParentChain(resourceNameObject, false /*allowDeferredResourceReference*/, false /*mustReturnDeferredResourceReference*/);
            if (value == DependencyProperty.UnsetValue)
            {
                ThrowException(nameof(SR.ParserNoResource) , $"{{{resourceNameObject}}}");
            }
 
            return value;
        }
 
        private object GetObjectDataFromContext(ReaderContextStackData context)
        {
            if (null == context.ObjectData &&
                null != context.ExpectedType)
            {
                Debug.Assert(!context.CreateUsingTypeConverter,
                    $"We had expected to use a TypeConverter for this {context.ExpectedType.FullName} but somebody is trying to create one now without using a TypeConverter.  If TypeConverter is the correct way, fix the code calling this method.  If not, fix the 'should we use a TypeConverter?' logic in XamlReaderHelper.");
 
                context.ObjectData = CreateInstanceFromType(context.ExpectedType,
                                                 context.ExpectedTypeId, true);
                if (null == context.ObjectData)
                {
                    ThrowException(nameof(SR.ParserCantCreateInstanceType), context.ExpectedType.FullName);
                }
 
                // Finish set up of the newly created element.
                context.ExpectedType = null; // Don't want to receive any other values
                ElementInitialize(context.ObjectData, null /*unknown name*/);
            }
            return context.ObjectData;
        }
 
        // A helper function to ensure that the current Element/ClrObject is created
        // before we add properties to it. This is called in situations where we have
        // given up hope of creating the object from text, and just need to create it
        // from a default constructor (if possible) in order to set one of its
        // attributes.
        internal object GetCurrentObjectData()
        {
            return GetObjectDataFromContext(CurrentContext);
        }
 
        // A helper function to ensure that the parent Element/ClrObject is created
        // before we add properties to it. This is called in situations where we have
        // given up hope of creating the object from text, and just need to create it
        // from a default constructor (if possible) in order to set one of its
        // attributes.
        protected object GetParentObjectData()
        {
            return GetObjectDataFromContext(ParentContext);
        }
 
        // Push context data onto the reader context stack
        internal void PushContext(
            ReaderFlags contextFlags,
            object      contextData,
            Type        expectedType,
            short       expectedTypeId)
        {
            PushContext( contextFlags, contextData, expectedType, expectedTypeId, false );
        }
 
        // Push context data onto the reader context stack
        internal void PushContext(
            ReaderFlags contextFlags,
            object      contextData,
            Type        expectedType,
            short       expectedTypeId,
            bool        createUsingTypeConverter)
        {
            ReaderContextStackData d;
 
            lock(_stackDataFactoryCache)
            {
                if (_stackDataFactoryCache.Count == 0)
                {
                    d = new ReaderContextStackData();
                }
                else
                {
                    // Get StackData from the factory cache
                    d = _stackDataFactoryCache[_stackDataFactoryCache.Count-1];
                    _stackDataFactoryCache.RemoveAt(_stackDataFactoryCache.Count-1);
                }
            }
 
            d.ContextFlags = contextFlags;
            d.ObjectData = contextData;
            d.ExpectedType = expectedType;
            d.ExpectedTypeId = expectedTypeId;
            d.CreateUsingTypeConverter = createUsingTypeConverter;
            ReaderContextStack.Push(d);
            ParserContext.PushScope();
 
            // If the context data is an object that implements INameScope, make it
            // the new Name scope for registering Names
 
            INameScope nameScope = NameScope.NameScopeFromObject(contextData);
 
            if (nameScope != null)
            {
                ParserContext.NameScopeStack.Push(nameScope);
            }
        }
 
        // Pos the reader context stack.
        internal void PopContext()
        {
            ReaderContextStackData stackData = (ReaderContextStackData) ReaderContextStack.Pop();
 
            // If we're through with an Name scoping point, take it off the stack.
            INameScope nameScope = NameScope.NameScopeFromObject(stackData.ObjectData);
 
            if (nameScope != null)
            {
                ParserContext.NameScopeStack.Pop();
            }
 
            ParserContext.PopScope();
 
            // Clear the stack data and then add it to the factory cache for reuse
            stackData.ClearData();
 
            lock(_stackDataFactoryCache)
            {
                _stackDataFactoryCache.Add(stackData);
            }
        }
 
        // Get BaseUri for the right elements.
        Uri GetBaseUri( )
        {
            Uri baseuri = ParserContext.BaseUri;
 
            if (baseuri == null)
            {
                baseuri = BindUriHelper.BaseUri;
            }
            else if (baseuri.IsAbsoluteUri == false)
            {
                baseuri = new Uri(BindUriHelper.BaseUri, baseuri);
            }
 
            return baseuri;
        }
 
 
        // Call various interfaces on the passed element during initialization or
        // creation of the element.  This is usually called immediately after
        // creating the object.
        // The bamlElementStartRecord may be null.   If it isn't, it represents the
        // record that caused this object to be created.
 
        private bool ElementInitialize(object element, string name)
        {
            bool result = false; // returns true if need to do EndInit()
 
            // Tell the Element Initialization has begun and hence postpone the Initialized event
            // If the element implements ISupportInitialize, call it.
            ISupportInitialize supportInitializeElement = element as ISupportInitialize;
            if (supportInitializeElement != null)
            {
                if( TraceMarkup.IsEnabled )
                {
                    TraceMarkup.Trace( TraceEventType.Start,
                                     TraceMarkup.BeginInit,
                                     supportInitializeElement );
                }
 
                supportInitializeElement.BeginInit();
                result = true;
 
                if( TraceMarkup.IsEnabled )
                {
                    TraceMarkup.Trace( TraceEventType.Stop,
                                     TraceMarkup.BeginInit,
                                     supportInitializeElement );
                }
            }
 
            // If this is an element start record that carries its name also, then register the name now.
 
            if (name != null)
            {
                DoRegisterName(name, element);
            }
 
 
            // Tell element its base uri
            IUriContext uriContext = element as IUriContext;
            if (uriContext != null)
            {
                uriContext.BaseUri = GetBaseUri();
            }
            else
            {
                // Set the ApplicationMarkupBaseUri if this is for AppDef baml stream.
                if (element is Application)
                {
                    ((Application)element).ApplicationMarkupBaseUri = GetBaseUri();
                }
            }
 
            UIElement uiElement = element as UIElement;
            if (uiElement != null)
            {
                uiElement.SetPersistId(++_persistId);
            }
 
            // The second consition is to handle events within standalone dictionaries.
            // We need to setup the component connector correctly in this case. Note
            // that the standalone dictionary is preceded by a DictionaryHolder.
            if (CurrentContext == null)
            {
                IComponentConnector icc = null;
                if (_componentConnector == null) // why was this necessary?
                {
                    _componentConnector = icc = element as IComponentConnector;
                    if (_componentConnector != null)
                    {
                        if (ParserContext.RootElement == null)
                        {
                            ParserContext.RootElement = element;
                        }
 
                        // Connect the root element.
                        _componentConnector.Connect(0, element);
                    }
                }
 
                _rootElement = element;
 
                DependencyObject doRoot = element as DependencyObject;
                if (!(element is INameScope)
                    && ParserContext.NameScopeStack.Count == 0
                    && (doRoot != null))
                {
                    NameScope namescope = null;
                    // if the root element is markup sub-classed and already is a namescope, use it.
                    if (icc != null)
                    {
                        namescope = NameScope.GetNameScope(doRoot) as NameScope;
                    }
                    if (namescope == null)
                    {
                        namescope = new NameScope();
                        NameScope.SetNameScope(doRoot, namescope);
                    }
                }
 
                if (doRoot != null)
                {
                    Uri baseuri = GetBaseUri();
                    SetDependencyValue(doRoot, BaseUriHelper.BaseUriProperty, baseuri);
                }
            }
 
            return result;
        }
 
        private void ElementEndInit(ref object element)
        {
            try
            {
                // Tell element initialization is complete since there are no more children.
                // If the element implements ISupportInitialize, call it.
                ISupportInitialize supportInitializeElement = element as ISupportInitialize;
                if (supportInitializeElement != null)
                {
                    if( TraceMarkup.IsEnabled )
                    {
                        TraceMarkup.Trace( TraceEventType.Start,
                                         TraceMarkup.EndInit,
                                         supportInitializeElement );
                    }
 
                    supportInitializeElement.EndInit();
 
                    if( TraceMarkup.IsEnabled )
                    {
                        TraceMarkup.Trace( TraceEventType.Stop,
                                         TraceMarkup.EndInit,
                                         supportInitializeElement );
                    }
                }
            }
            catch( Exception e )
            {
                if( CriticalExceptions.IsCriticalException(e) || e is XamlParseException )
                {
                    throw;
                }
 
                // Check if the ParentContext represents a property
 
                ReaderContextStackData parentContext = ParentContext;
                ReaderFlags parentContextType = parentContext != null ? parentContext.ContextType : ReaderFlags.Unknown;
 
                if (parentContextType == ReaderFlags.PropertyComplexClr ||
                    parentContextType == ReaderFlags.PropertyComplexDP ||
                    parentContextType == ReaderFlags.PropertyIList ||
                    parentContextType == ReaderFlags.PropertyIDictionary ||
                    parentContextType == ReaderFlags.PropertyArray ||
                    parentContextType == ReaderFlags.PropertyIAddChild)
                {
                    // Check if the GrandParent object implements IProvidePropertyFallback
 
                    IProvidePropertyFallback iProvidePropertyFallback = GrandParentObjectData as IProvidePropertyFallback;
                    if (iProvidePropertyFallback != null)
                    {
                        // Find the property name from the ParentContext
 
                        string propertyName = parentContext.ElementNameOrPropertyName;
 
                        // Check if the GrandParent object can provide a property fallback value
 
                        if (iProvidePropertyFallback.CanProvidePropertyFallback(propertyName))
                        {
                            element = iProvidePropertyFallback.ProvidePropertyFallback(propertyName, e);
 
                            // Place the element back into the context
                            CurrentContext.ObjectData = element;
 
                            return;
                        }
                    }
                }
 
                ThrowExceptionWithLine( SR.ParserFailedEndInit, e );
            }
        }
 
        // Checks if the last element on the stack needs to be added to the Tree and
        // if it does adds it. This is done if a CLR or Dependency object is on the
        // stack and the parent object implements IAddChild or IList, and the parent
        // context is an object context.
        // Set AddedToTree context flag if an object was added to its parent via IAddChild or IList.
        private void SetPropertyValueToParent(bool fromStartTag)
        {
            bool isMarkupExtension;
            SetPropertyValueToParent(fromStartTag, out isMarkupExtension);
        }
 
        private void SetPropertyValueToParent(bool fromStartTag, out bool isMarkupExtension)
        {
            isMarkupExtension = false;
            object traceCurrentObject = null;
 
 
            ReaderContextStackData currentContext = CurrentContext;
            ReaderContextStackData parentContext = ParentContext;
 
            if (currentContext == null ||
                !currentContext.NeedToAddToTree ||
                (ReaderFlags.DependencyObject != currentContext.ContextType &&
                 ReaderFlags.ClrObject != currentContext.ContextType))
            {
                return;
            }
 
            object currentObject = null;
 
#if !STRESS
            try
            {
#endif
                currentObject = GetCurrentObjectData();
 
                // Call FreezeIfRequired to ensure objects are Frozen before they are added to the tree
                //
                // To avoid propagating changed notifiers, make sure to Freeze objects before adding
                // them.  When called from ReadElementEndRecord, this will actually cause the object
                // to be Frozen twice (once now, and once during ReadElementEndRecord).  The second
                // call to Freeze has no affect since the object's already frozen.
                //
                // The second call to Freeze could be avoided by checking the IsFrozen flag in
                // FreezeIfRequired, or by checking for ReaderFlags.AddedToTree after this call is
                // finished.  However, this code-path isn't used for the common Freezable
                // case (Property syntax), so we're choosing to call Freeze twice in the uncommon case
                // instead of either of those checks in the common case (i.e., every element).
 
                FreezeIfRequired(currentObject);
 
 
                // If we don't have a parent, this is the root.
 
                if (null == parentContext)
                {
                    if (RootList.Count == 0)
                    {
                        RootList.Add(currentObject);
                    }
 
                    currentContext.MarkAddedToTree();
                    return;
                }
 
                // If we're under a collection-typed property, this object may be the collection itself,
                // or may be an item in the collection.  Check that here.
 
                if (CheckExplicitCollectionTag(ref isMarkupExtension))
                {
                    // This object was the collection itself, not just an item, so we're done.
                    currentContext.MarkAddedToTree();
                    return;
                }
 
                // Otherwise, get the parent.  The rest of the routine we decide how to add to it.
 
                object parent = GetParentObjectData();
 
                // Handle parent as a dictionary:
 
                IDictionary dictionary = GetDictionaryFromContext(parentContext, true /*toInsert*/);
                if (dictionary != null)
                {
                    // if this SetPropertyValueToParent call occurred during ReadElementStart, then we
                    // don't have a key for this element yet, and should wait until ReadElementEnd
                    if (!fromStartTag)
                    {
                        currentObject = GetElementValue(currentObject, dictionary, null /*contentProperty*/, ref isMarkupExtension);
 
                        if (currentContext.Key == null)
                        {
                            // throw an exception if this element does not have a key
                            ThrowException(nameof(SR.ParserNoDictionaryKey));
                        }
 
                        dictionary.Add(currentContext.Key, currentObject);
 
                        currentContext.MarkAddedToTree();
                    }
 
                    return;
                }
 
                // Handle parent as an IList:
 
                IList list = GetListFromContext(parentContext);
                if (list != null)
                {
                    currentObject = GetElementValue(currentObject, list, null /*contentProperty*/, ref isMarkupExtension);
 
                    list.Add(currentObject);
 
                    currentContext.MarkAddedToTree();
                    return;
                }
 
                // Handle parent as an array:
 
                ArrayExtension arrayExt = GetArrayExtensionFromContext(parentContext);
                if (arrayExt != null)
                {
                    currentObject = GetElementValue(currentObject, arrayExt, null /*contentProperty*/, ref isMarkupExtension);
 
                    arrayExt.AddChild(currentObject);
 
                    if( TraceMarkup.IsEnabled )
                    {
                        TraceMarkup.Trace( TraceEventType.Stop,
                                         TraceMarkup.AddValueToArray,
                                         traceCurrentObject,
                                         parentContext.ElementNameOrPropertyName,
                                         currentObject );
                    }
 
                    currentContext.MarkAddedToTree();
                    return;
                }
 
                // Handle parent as IAddChild:
 
                IAddChild iac = GetIAddChildFromContext(parentContext);
                if (iac != null)
                {
                    currentObject = GetElementValue(currentObject, iac, null /*contentProperty*/, ref isMarkupExtension);
 
                    // The object may have changed to a string if it was a MarkupExtension
                    // that returned a string from ProvideValue, so check for this and
                    // call the appropriate IAddChild method.
                    string text = currentObject as string;
 
                    if (text != null)
                    {
                        iac.AddText(text);
                    }
                    else
                    {
                        iac.AddChild(currentObject);
                    }
 
                    if( TraceMarkup.IsEnabled )
                    {
                        TraceMarkup.Trace( TraceEventType.Stop,
                                         TraceMarkup.AddValueToAddChild,
                                         traceCurrentObject,
                                         currentObject );
                    }
 
                    currentContext.MarkAddedToTree();
                    return;
                }
 
                // Handle parent as CPA:
 
                object contentProperty = parentContext.ContentProperty;
                if (contentProperty != null)
                {
                    currentObject = GetElementValue(currentObject, parentContext.ObjectData, contentProperty, ref isMarkupExtension);
                    AddToContentProperty(parent, contentProperty, currentObject); // Traces to TraceXamnl
 
                    currentContext.MarkAddedToTree();
                    return;
                }
 
                // Handle parent as a singleton property:
 
                if( parentContext.ContextType == ReaderFlags.PropertyComplexClr )
                {
                    object parentObject = GetObjectDataFromContext(GrandParentContext);
                    MemberInfo memberInfo = (MemberInfo)GetParentObjectData();
 
                    SetClrComplexProperty(parentObject, memberInfo, currentObject);// Traces to TraceXamnl
                    currentContext.MarkAddedToTree();
                    return;
                }
 
                if( parentContext.ContextType == ReaderFlags.PropertyComplexDP )
                {
                    object parentObject = GetObjectDataFromContext(GrandParentContext);
                    BamlAttributeInfoRecord attribInfo = (BamlAttributeInfoRecord)GetParentObjectData();
 
                    SetDependencyComplexProperty(parentObject, attribInfo, currentObject);// Traces to TraceXamnl
                    currentContext.MarkAddedToTree();
                    return;
                }
 
                // If we get here there was no way to set the value to the parent, error:
 
                Type parentType = GetParentType();
                string typeName = parentType == null ? String.Empty : parentType.FullName;
 
                if( currentObject == null )
                    ThrowException( nameof(SR.ParserCannotAddAnyChildren), typeName );
                else
                    ThrowException( nameof(SR.ParserCannotAddAnyChildren2), typeName, currentObject.GetType().FullName );
 
#if !STRESS
            }
 
            catch( Exception e )
            {
                if( CriticalExceptions.IsCriticalException(e) || e is XamlParseException )
                {
                    throw;
                }
 
                Type parentType = GetParentType();
                string typeName = parentType == null ? String.Empty : parentType.FullName;
 
                if( currentObject == null )
                    ThrowException( nameof(SR.ParserCannotAddAnyChildren), typeName );
                else
                    ThrowException( nameof(SR.ParserCannotAddAnyChildren2), typeName, currentObject.GetType().FullName );
            }
#endif
 
        }
 
 
        // Determine the parent type from the context stack data.
 
        private Type GetParentType()
        {
            ReaderContextStackData parentContext = ParentContext;
            object parent = GetParentObjectData();
 
            if (parentContext.CheckFlag(ReaderFlags.CollectionHolder))
            {
                parent = ((BamlCollectionHolder)parent).Collection;
            }
 
            if (parent != null)
            {
                return parent.GetType();
            }
            else if (parentContext.ExpectedType != null)
            {
                return parentContext.ExpectedType;
            }
 
            return null;
        }
 
        private object GetElementValue(object element, object parent, object contentProperty, ref bool isMarkupExtension)
        {
            // The element may be a MarkupExtension, so get its value if that's the case
            // and use that as the element.
            MarkupExtension me = element as MarkupExtension;
            if (me != null)
            {
                isMarkupExtension = true;
                element = ProvideValueFromMarkupExtension(me, parent, contentProperty);
                CurrentContext.ObjectData = element;
            }
 
            return element;
        }
 
        // this method checks the current context to see if it is the context of a property collection
        // and sets that property's value to the current element if the type is assignable to the type
        // of the property.  If not then, it returns false and the element should be added to the tree.
        private bool CheckExplicitCollectionTag(ref bool isMarkupExtension)
        {
            bool result = false;
            ReaderContextStackData parentContext = ParentContext;
 
            // if the parent context is a BamlCollectionHolder, and has not been set, then continue check
            if (parentContext != null &&
                parentContext.CheckFlag(ReaderFlags.CollectionHolder) &&
                parentContext.ExpectedType != null)
            {
                BamlCollectionHolder holder = (BamlCollectionHolder)parentContext.ObjectData;
 
                if (!holder.IsClosed && !holder.ReadOnly)
                {
                    ReaderContextStackData currentContext = CurrentContext;
                    object element = currentContext.ObjectData;
                    Type elementType;
 
                    if (currentContext.CheckFlag(ReaderFlags.ArrayExt))
                    {
                        // arrays are a little different because we have to get the type of the
                        // elements to be stored in the array and make an array type from it
                        elementType = ((ArrayExtension)element).Type.MakeArrayType();
 
                        // in case of an explicit tag, we don't resolve this markup extension until ReadPropertyArrayEndRecord
                        isMarkupExtension = false;
                    }
                    else
                    {
                        // the parent is a BamlCollectionHolder representing the property which may
                        // represent the explicit collection and the grandparent is that property's target.
                        element = GetElementValue(element, GrandParentObjectData,
                                                  holder.PropertyDefinition.DependencyProperty, ref isMarkupExtension);
                        elementType = element == null ? null : element.GetType();
                    }
 
                    // the element is an explicit collection if it is assignable to the expected type of the parent or
                    // it is a MarkupExtension, which means we don't know what it's type will be.
                    if (isMarkupExtension || parentContext.ExpectedType.IsAssignableFrom(elementType))
                    {
                        // if the the property's expected type matches the element type, assign the
                        // collection holder's collection to be this element
                        holder.Collection = element;
                        holder.IsClosed = true;
                        parentContext.ExpectedType = null;
                        result = true;
                    }
                }
            }
 
            return result;
        }
 
        private void AddToContentProperty(object container, object contentProperty, object value)
        {
            Debug.Assert(contentProperty != null);
            IList contentList = contentProperty as IList;
            object traceCurrentObject = null;
 
#if !STRESS
            try
            {
#endif
 
                // Adding to a collection?
 
                if (contentList != null)
                {
                    if( TraceMarkup.IsEnabled )
                    {
                        TraceMarkup.Trace( TraceEventType.Start,
                                         TraceMarkup.AddValueToList,
                                         traceCurrentObject,
                                         String.Empty,
                                         value);
                    }
 
                    contentList.Add(value);
 
                    if( TraceMarkup.IsEnabled )
                    {
                        TraceMarkup.Trace( TraceEventType.Stop,
                                         TraceMarkup.AddValueToList,
                                         traceCurrentObject,
                                         String.Empty,
                                         value);
                    }
                }
                else
                {
                    // Setting to a DP?
 
                    DependencyProperty dp = contentProperty as DependencyProperty;
                    if (dp != null)
                    {
                        DependencyObject dpo = container as DependencyObject;
                        if (dpo == null)
                        {
                            // ?? This appears to be old code, we shouldn't ever get into this path.
                            ThrowException(nameof(SR.ParserParentDO), value.ToString());
                        }
 
                        if( TraceMarkup.IsEnabled )
                        {
                            TraceMarkup.Trace( TraceEventType.Start,
                                             TraceMarkup.SetPropertyValue,
                                             traceCurrentObject,
                                             dp.Name,
                                             value);
                        }
 
                        SetDependencyValue(dpo, dp, value);
 
                        if( TraceMarkup.IsEnabled )
                        {
                            TraceMarkup.Trace( TraceEventType.Stop,
                                             TraceMarkup.SetPropertyValue,
                                             traceCurrentObject,
                                             dp.Name,
                                             value);
                        }
                    }
                    else
                    {
                        // Setting to a CLR property?
 
                        PropertyInfo pi = contentProperty as PropertyInfo;
                        if (pi != null)
                        {
                            if( TraceMarkup.IsEnabled )
                            {
                                TraceMarkup.Trace( TraceEventType.Start,
                                                 TraceMarkup.SetPropertyValue,
                                                 traceCurrentObject,
                                                 pi.Name,
                                                 value);
                            }
 
 
                            bool set = XamlTypeMapper.SetInternalPropertyValue(ParserContext,
                                                                               ParserContext.RootElement,
                                                                               pi,
                                                                               container,
                                                                               value);
                            if (!set)
                            {
                                ThrowException(nameof(SR.ParserCantSetContentProperty), pi.Name, pi.ReflectedType.Name);
                            }
 
                            if( TraceMarkup.IsEnabled )
                            {
                                TraceMarkup.Trace( TraceEventType.Stop,
                                                 TraceMarkup.SetPropertyValue,
                                                 traceCurrentObject,
                                                 pi.Name,
                                                 value);
                            }
                        }
                        else
                        {
                            Debug.Assert(false, "The only remaining option is attached property, which is not allowed in xaml for content properties");
                        }
                    }
                }
#if !STRESS
            }
            catch (Exception e)
            {
                if( CriticalExceptions.IsCriticalException(e) || e is XamlParseException )
                {
                    throw;
                }
 
                ThrowExceptionWithLine(
                    SR.Format(SR.ParserCannotAddChild,
                           value.GetType().Name,
                           container.GetType().Name),
                        e);
            }
#endif
 
            if( TraceMarkup.IsEnabled )
            {
                TraceMarkup.Trace( TraceEventType.Stop,
                                 TraceMarkup.SetCPA,
                                 traceCurrentObject,
                                 value);
            }
        }
 
        // Given a id looks up in the Map table to find the
        // associated attributeinfo for clr properties and returns the property name
        internal string GetPropertyNameFromAttributeId(short id)
        {
            if (null != MapTable)
            {
                return MapTable.GetAttributeNameFromId(id);
            }
 
            return null;
        }
 
        // Given an ID looks up in the Map table to find the
        // associated attributeinfo for clr properties and returns the property name
        internal string GetPropertyValueFromStringId(short id)
        {
            string propertyValue = null;
 
            if (null != MapTable)
            {
                propertyValue = MapTable.GetStringFromStringId(id);
            }
 
            return propertyValue;
        }
 
        // Create a serializer, given a type info record with serializer information.
        private XamlSerializer CreateSerializer(
            BamlTypeInfoWithSerializerRecord typeWithSerializerInfo)
        {
            // ID less than 0 means a known serializer in PresentationFramework.
            if (typeWithSerializerInfo.SerializerTypeId < 0)
            {
                return (XamlSerializer)MapTable.CreateKnownTypeFromId(
                                    typeWithSerializerInfo.SerializerTypeId);
            }
            else
            {
                // If the serializer type hasn't been determined yet, do it now.
                if (typeWithSerializerInfo.SerializerType == null)
                {
                    typeWithSerializerInfo.SerializerType = MapTable.GetTypeFromId(
                                             typeWithSerializerInfo.SerializerTypeId);
                }
                return (XamlSerializer)CreateInstanceFromType(
                             typeWithSerializerInfo.SerializerType,
                             typeWithSerializerInfo.SerializerTypeId,
                             false);
            }
        }
 
        internal object GetREOrEiFromAttributeId(
                short id,
            out bool isInternal,
            out bool isRE)
        {
            object info = null;
            isRE = true;
            isInternal = false;
            BamlAttributeInfoRecord attribInfo = null;
 
            if (null != MapTable)
            {
                attribInfo = MapTable.GetAttributeInfoFromId(id);
                if (null != attribInfo)
                {
                    info = attribInfo.Event;
                    if (info == null)
                    {
                        info = attribInfo.EventInfo;
                        if (info == null)
                        {
                            attribInfo.Event = MapTable.GetRoutedEvent(attribInfo);
                            info = attribInfo.Event;
                            if (info == null)
                            {
                                Object currentParent = GetCurrentObjectData();
                                Type   currentParentType;
                                currentParentType = currentParent.GetType();
 
                                if (ReflectionHelper.IsPublicType(currentParentType))
                                {
                                    attribInfo.EventInfo = ParserContext.XamlTypeMapper.GetClrEventInfo(currentParentType, attribInfo.Name);
                                }
 
                                if (attribInfo.EventInfo == null)
                                {
                                    attribInfo.EventInfo = currentParentType.GetEvent(attribInfo.Name,
                                                                BindingFlags.Instance |
                                                                BindingFlags.Public |
                                                                BindingFlags.NonPublic);
 
                                    if (attribInfo.EventInfo != null)
                                    {
                                        attribInfo.IsInternal = true;
                                    }
                                }
 
                                info = attribInfo.EventInfo;
                                isRE = false;
                            }
                        }
                        else
                        {
                            isRE = false;
                        }
                    }
                }
            }
 
            if (attribInfo != null)
            {
                isInternal = attribInfo.IsInternal;
            }
            return info;
        }
 
        // Helper method to get the OwnerType.PropertyName string from a
        // attribute info record or PropertyInfo.  This is used
        // primarily for error reporting
        private string GetPropNameFrom(object PiOrAttribInfo)
        {
            BamlAttributeInfoRecord attribInfo = PiOrAttribInfo as BamlAttributeInfoRecord;
            if (attribInfo != null)
            {
                return $"{attribInfo.OwnerType.Name}.{attribInfo.Name}";
            }
            else
            {
                PropertyInfo pi = PiOrAttribInfo as PropertyInfo;
                if (pi != null)
                {
                    return $"{pi.DeclaringType.Name}.{pi.Name}";
                }
                else
                {
                    return string.Empty;
                }
            }
        }
 
        //
        // ThrowException wrappers for 0-3 parameter SRIDs
        //
 
        protected void ThrowException(
             string    id)
        {
            ThrowExceptionWithLine(SR.GetResourceString(id), null);
        }
 
        protected internal void ThrowException(
            string     id,
            string     parameter)
        {
            ThrowExceptionWithLine(SR.Format(SR.GetResourceString(id), parameter), null);
        }
 
        protected void ThrowException(
            string     id,
            string     parameter1,
            string     parameter2)
        {
            ThrowExceptionWithLine(SR.Format(SR.GetResourceString(id), parameter1, parameter2), null);
        }
 
        protected void ThrowException(
            string     id,
            string     parameter1,
            string     parameter2,
            string     parameter3)
        {
            ThrowExceptionWithLine(SR.Format(SR.GetResourceString(id), parameter1, parameter2, parameter3), null);
        }
 
        // Helper to insert line and position numbers into message, if they are present
        internal void ThrowExceptionWithLine(string message, Exception innerException)
        {
            XamlParseException.ThrowException(ParserContext, LineNumber, LinePosition, message, innerException);
        }
 
        // Helper method to creates an instance of the specified type
        internal object CreateInstanceFromType(
            Type  type,
            short typeId,
            bool  throwOnFail)
        {
            bool publicOnly = true;
            BamlTypeInfoRecord typeInfo = null;
            if (typeId >= 0)
            {
                typeInfo = MapTable.GetTypeInfoFromId(typeId);
                if (typeInfo != null)
                {
                    publicOnly = !typeInfo.IsInternalType;
                }
            }
 
            if (publicOnly)
            {
                if (!ReflectionHelper.IsPublicType(type))
                {
                    ThrowException(nameof(SR.ParserNotMarkedPublic), type.Name);
                }
            }
            else
            {
                if (!ReflectionHelper.IsInternalType(type))
                {
                    ThrowException(nameof(SR.ParserNotAllowedInternalType), type.Name);
                }
            }
 
#if !STRESS
            try
            {
#endif
                EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose, EventTrace.Event.WClientParseRdrCrInFTypBegin);
 
                object instance = null;
                try
                {
                    if (TraceMarkup.IsEnabled)
                    {
                        TraceMarkup.Trace(TraceEventType.Start,
                                         TraceMarkup.CreateObject,
                                         type);
                    }
 
                    // String is a very common object that we can try to create, but it will always
                    // fail since it has no default constructor.  Check for this case to avoid throwing
                    // an expensive exception
                    if (type != typeof(String))
                    {
                        if (typeId < 0)
                        {
                            instance = MapTable.CreateKnownTypeFromId(typeId);
                        }
                        else if (publicOnly)
                        {
                            // Don't use the CreateInstance(Type,BindingFlags) overload, as it's a lot more expensive.
                            instance = Activator.CreateInstance(type);
                        }
                        else
                        {
                            instance = XamlTypeMapper.CreateInternalInstance(ParserContext, type);
                            if (instance == null && throwOnFail)
                            {
                                ThrowException(nameof(SR.ParserNotAllowedInternalType), type.Name);
                            }
                        }
                    }
 
                    if (TraceMarkup.IsEnabled)
                    {
                        TraceMarkup.Trace(TraceEventType.Stop,
                                         TraceMarkup.CreateObject,
                                         type,
                                         instance);
                    }
                }
                finally
                {
                    EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose, EventTrace.Event.WClientParseRdrCrInFTypEnd);
                }
                return instance;
#if !STRESS
            }
 
            catch (System.MissingMethodException e)
            {
               if (throwOnFail)
               {
                   // If we are setting a complex property, it may be that we have
                   // inserted an element tag that the user is not aware of, so
                   // give a more detailed error message.  Otherwise just complain
                   // that the type cannot be created.
                   if (ParentContext != null &&
                       ParentContext.ContextType == ReaderFlags.PropertyComplexDP)
                   {
                       BamlAttributeInfoRecord attribInfo = GetParentObjectData() as BamlAttributeInfoRecord;
                       ThrowException(nameof(SR.ParserNoDefaultPropConstructor),
                                      type.Name, attribInfo.DP.Name);
                   }
                   else
                   {
                       ThrowExceptionWithLine(SR.Format(SR.ParserNoDefaultConstructor, type.Name), e );
                   }
               }
 
               // No zero parameter constructor.  Return null.
               return null;
            }
 
            catch (Exception e)
            {
                if( CriticalExceptions.IsCriticalException(e) || e is XamlParseException )
                {
                    throw;
                }
 
                ThrowExceptionWithLine( SR.Format(SR.ParserErrorCreatingInstance, type.Name, type.Assembly.FullName), e);
                return null;
            }
#endif
        }
 
        // Freeze the object if it a Freezeable, and PresentationOptions:Freeze
        // has been specified.  This method is called after the Freezable
        // has been fully created and is ready to be set on it's parent.
        internal void FreezeIfRequired(object element)
        {
            if (_parserContext.FreezeFreezables)
            {
                Freezable f = element as Freezable;
                if (f != null)
                {
                    f.Freeze();
                }
            }
        }
        internal void PreParsedBamlReset()
        {
            PreParsedCurrentRecord = PreParsedRecordsStart;
        }
 
 
        //+--------------------------------------------------------------------------------------------------------------
        //
        //  SetPreviousBamlRecordReader
        //
        //  Link this nested BamlRecordReader to one that is higher in the stack.
        //
        //+--------------------------------------------------------------------------------------------------------------
 
        protected internal void SetPreviousBamlRecordReader( BamlRecordReader previousBamlRecordReader )
        {
            _previousBamlRecordReader = previousBamlRecordReader;
        }
 
        #endregion Methods
 
        #region Properties
 
        // List of preparsed BamlRecords that are used instead of a
        // record stream.  This is used when reading the contents of
        // a resource dictionary.
        internal BamlRecord PreParsedRecordsStart
        {
            get { return _preParsedBamlRecordsStart; }
            set { _preParsedBamlRecordsStart = value; }
        }
 
        // Index into the list of preparsed records for the next
        // record to be read.
        internal BamlRecord PreParsedCurrentRecord
        {
            get { return _preParsedIndexRecord; }
            set { _preParsedIndexRecord= value; }
        }
 
        // Stream that contains baml records in binary form.  This is used when
        // reading from a file.
        internal Stream BamlStream
        {
            get { return _bamlStream; }
 
            set
            {
                _bamlStream =  value;
 
                // if this is one of our Readers streams
                // setup the XAMLReaderStream property.
                if (_bamlStream is ReaderStream)
                {
                    _xamlReaderStream = (ReaderStream) _bamlStream;
                }
                else
                {
                    _xamlReaderStream = null;
                }
 
                if (BamlStream != null)
                {
                    _binaryReader = new BamlBinaryReader(BamlStream, new System.Text.UTF8Encoding());
                }
            }
        }
 
        // review, should be private
        internal BamlBinaryReader BinaryReader
        {
            get { return _binaryReader; }
        }
 
        internal XamlTypeMapper XamlTypeMapper
        {
            get { return ParserContext.XamlTypeMapper; }
        }
 
        internal ParserContext ParserContext
        {
            get { return _parserContext; }
            set
            {
                // Ensure that the parser context always has the reader
                // assigned to it.  This is required for parse time resource
                // searches.
                _parserContext = value;
 
                // Reset the TypeConvertContext cache because it might have
                // cached the old ParserContext that we just changed.
                _typeConvertContext = null;
            }
        }
 
        internal TypeConvertContext TypeConvertContext
        {
            get
            {
                if (null == _typeConvertContext)
                {
                    _typeConvertContext = new TypeConvertContext(ParserContext);
                }
                return _typeConvertContext;
            }
        }
 
        // Determines sync and async parsing modes.  Not used directly by the record
        // reader, but is needed when spinning off other deserializers
        internal XamlParseMode XamlParseMode
        {
            get { return _parseMode; }
            set { _parseMode = value; }
        }
 
        // The maximum number of records to read while in async mode
        internal int MaxAsyncRecords
        {
            get { return _maxAsyncRecords; }
            set { _maxAsyncRecords = value; }
        }
 
        // Table for mapping types, attributes and assemblies.
        // This should always be a part of the ParserContext
        internal BamlMapTable MapTable
        {
            get { return ParserContext.MapTable; }
        }
 
        // Maps namespace prefixes (key) to XML namespaces (value)
        internal XmlnsDictionary XmlnsDictionary
        {
            get { return ParserContext.XmlnsDictionary; }
        }
 
        internal ReaderContextStackData CurrentContext
        {
            get { return (ReaderContextStackData) ReaderContextStack.CurrentContext; }
        }
 
        internal ReaderContextStackData ParentContext
        {
            get { return (ReaderContextStackData) ReaderContextStack.ParentContext; }
        }
 
        internal object ParentObjectData
        {
            get
            {
                ReaderContextStackData contextData = ParentContext;
                return contextData == null ? null : contextData.ObjectData;
            }
        }
 
        internal ReaderContextStackData GrandParentContext
        {
            get { return (ReaderContextStackData) ReaderContextStack.GrandParentContext; }
        }
 
        internal object GrandParentObjectData
        {
            get
            {
                ReaderContextStackData contextData = GrandParentContext;
                return contextData == null ? null : contextData.ObjectData;
            }
        }
 
        internal ReaderContextStackData GreatGrandParentContext
        {
            get { return (ReaderContextStackData) ReaderContextStack.GreatGrandParentContext; }
        }
 
        internal ParserStack ReaderContextStack
        {
            get { return _contextStack; }
        }
 
        internal BamlRecordManager BamlRecordManager
        {
            get
            {
                if( _bamlRecordManager == null )
                {
                    _bamlRecordManager = new BamlRecordManager();
                }
 
                return _bamlRecordManager;
            }
        }
 
        internal bool EndOfDocument
        {
            get { return _endOfDocument;}
            set { _endOfDocument = value; }
        }
 
        /// <summary>
        /// Element that is the Root of this document. Can be null
        /// if current Root is not an Element
        /// </summary>
        internal object RootElement
        {
            get { return _rootElement; }
            set { _rootElement = value; }
        }
 
        internal IComponentConnector ComponentConnector
        {
            get { return _componentConnector; }
            set { _componentConnector = value; }
        }
 
        ReaderStream XamlReaderStream
        {
            get { return _xamlReaderStream; }
        }
 
        // The stack of context information accumulated during reading.
        internal ParserStack ContextStack
        {
            get { return _contextStack; }
            set { _contextStack = value; }
        }
 
        internal int LineNumber
        {
            get { return ParserContext.LineNumber; }
            set { ParserContext.LineNumber = value; }
        }
 
        internal int LinePosition
        {
            get { return ParserContext.LinePosition; }
            set { ParserContext.LinePosition = value; }
        }
 
        internal bool IsDebugBamlStream
        {
            get { return ParserContext.IsDebugBamlStream; }
            set { ParserContext.IsDebugBamlStream = value; }
        }
 
        internal Int64 StreamPosition
        {
            get { return _bamlStream.Position; }
        }
 
        Int64 StreamLength
        {
            get { return _bamlStream.Length; }
        }
 
        internal bool IsRootAlreadyLoaded
        {
            get { return _isRootAlreadyLoaded; }
            set { _isRootAlreadyLoaded = value; }
        }
 
        // The PreviousBamlRecordReader is set when this BRR is nested inside
        // another.
 
        internal BamlRecordReader PreviousBamlRecordReader
        {
            get { return _previousBamlRecordReader; }
        }
 
#endregion Properties
 
#region Data
 
        // state vars
        IComponentConnector          _componentConnector;
        object                       _rootElement;
        bool                         _bamlAsForest;
        bool                         _isRootAlreadyLoaded;
        ArrayList                    _rootList;
        ParserContext                _parserContext;   // XamlTypeMapper, namespace state, lang/space values
        TypeConvertContext           _typeConvertContext;
        int                          _persistId;
        ParserStack                  _contextStack = new ParserStack();
        XamlParseMode                _parseMode = XamlParseMode.Synchronous;
        int                          _maxAsyncRecords;
        // end of state vars
 
        Stream                       _bamlStream;
        ReaderStream                 _xamlReaderStream;
        BamlBinaryReader             _binaryReader;
        BamlRecordManager            _bamlRecordManager;
        BamlRecord                   _preParsedBamlRecordsStart = null;
        BamlRecord                   _preParsedIndexRecord = null;
        bool                         _endOfDocument = false;
        bool                         _buildTopDown = true;
 
        // The outer BRR, when this one is nested.
        BamlRecordReader             _previousBamlRecordReader;
 
        static List<ReaderContextStackData> _stackDataFactoryCache = new List<ReaderContextStackData>();
 
#endregion Data
    }
 
    /// <summary>
    /// This class is used in the resolution of a StaticResourceId. It is used to cache the
    /// prefetched value during that processing. We have sub-classed StaticResourceExtension
    /// so that we do not need to take the cost of increasing the size of a StaticResourceExtension
    /// by 4 bytes.
    /// </summary>
    internal class StaticResourceHolder : StaticResourceExtension
    {
        #region Constructors
 
        internal StaticResourceHolder(object resourceKey, DeferredResourceReference prefetchedValue) : base(resourceKey)
        {
            _prefetchedValue = prefetchedValue;
        }
 
        #endregion Constructors
 
        #region Methods
 
        internal override DeferredResourceReference PrefetchedValue
        {
            get { return _prefetchedValue; }
        }
 
        #endregion Methods
 
        #region Data
 
        private DeferredResourceReference _prefetchedValue;
 
        #endregion Data
    }
 
    // This structure is usedas a generilized property descriptor.
    // It can have three possible states - DependencyProperty, PropertyInfo, AttachedPropertyGetter/Setter.
    // PropertyInfo is used for CLR properties, AttachedPropertySetter is used for attached properties.
    // DependencyProperty is used as an optimization for either CLr or Attached property when it is backed by a DP.
    internal struct WpfPropertyDefinition
    {
        public WpfPropertyDefinition(BamlRecordReader reader, short attributeId, bool targetIsDependencyObject)
        {
            _reader = reader;
            _attributeId = attributeId;
            _dependencyProperty = null;
            _attributeInfo = null;
 
            if (_reader.MapTable != null && targetIsDependencyObject)
            {
                _dependencyProperty = _reader.MapTable.GetDependencyProperty(_attributeId);
            }
        }
 
        public DependencyProperty DependencyProperty
        {
            get
            {
                return _dependencyProperty;
            }
        }
 
        public BamlAttributeUsage AttributeUsage
        {
            get
            {
                if (_attributeInfo != null)
                {
                    return _attributeInfo.AttributeUsage;
                }
                else if (_reader.MapTable != null)
                {
                    short ownerTypeId;
                    string name;
                    BamlAttributeUsage attributeUsage;
                    _reader.MapTable.GetAttributeInfoFromId(_attributeId, out ownerTypeId, out name, out attributeUsage);
                    return attributeUsage;
                }
                else
                {
                    return BamlAttributeUsage.Default;
                }
            }
        }
 
        public BamlAttributeInfoRecord AttributeInfo
        {
            get
            {
                if (_attributeInfo == null && _reader.MapTable != null)
                {
                    // Either the attribute is not a DP or the record is still needed.
                    // This version of the method makes sure that attributeInfo.OwnerType is calculated.
                    // In most other cases we ant to avoid unnecessary type allocations.
                    _attributeInfo = _reader.MapTable.GetAttributeInfoFromIdWithOwnerType(_attributeId);
                    Debug.Assert(_attributeInfo != null);
                }
                return _attributeInfo;
            }
        }
 
        public PropertyInfo PropertyInfo
        {
            get
            {
                if (this.AttributeInfo == null)
                {
                    return null;
                }
 
                if (_attributeInfo.PropInfo == null)
                {
                    Object currentParent = _reader.GetCurrentObjectData();
                    Type currentParentType = currentParent.GetType();
 
                    _reader.XamlTypeMapper.UpdateClrPropertyInfo(currentParentType, _attributeInfo);
                }
 
                return _attributeInfo.PropInfo;
            }
        }
 
        public MethodInfo AttachedPropertyGetter
        {
            get
            {
                if (this.AttributeInfo == null)
                {
                    return null;
                }
 
                if (_attributeInfo.AttachedPropertyGetter == null)
                {
                    _reader.XamlTypeMapper.UpdateAttachedPropertyGetter(_attributeInfo);
                }
 
                return _attributeInfo.AttachedPropertyGetter;
            }
        }
 
        public MethodInfo AttachedPropertySetter
        {
            get
            {
                if (this.AttributeInfo == null)
                {
                    return null;
                }
 
                if (_attributeInfo.AttachedPropertySetter == null)
                {
                    // Note we update both Setter and Getter in one call; and detect the need of it by Getter==null
                    _reader.XamlTypeMapper.UpdateAttachedPropertySetter(_attributeInfo);
                }
 
                return _attributeInfo.AttachedPropertySetter;
            }
        }
 
        public bool IsInternal
        {
            get
            {
                if (this.AttributeInfo == null)
                {
                    return false;
                }
 
                return _attributeInfo.IsInternal;
            }
        }
 
        public Type PropertyType
        {
            get
            {
                if (this.DependencyProperty != null)
                {
                    return this.DependencyProperty.PropertyType;
                }
                else if (this.PropertyInfo != null)
                {
                    return this.PropertyInfo.PropertyType;
                }
                else if (this.AttachedPropertySetter != null)
                {
                    return XamlTypeMapper.GetPropertyType(this.AttachedPropertySetter);
                }
                else
                {
                    Debug.Assert(this.AttachedPropertyGetter != null);
                    return this.AttachedPropertyGetter.ReturnType;
                }
            }
        }
 
        public string Name
        {
            get
            {
                if (this.DependencyProperty != null)
                {
                    return this.DependencyProperty.Name;
                }
                else if (this.PropertyInfo != null)
                {
                    return this.PropertyInfo.Name;
                }
                else if (this.AttachedPropertySetter != null)
                {
                    return this.AttachedPropertySetter.Name.Substring("Set".Length);
                }
                else if (this.AttachedPropertyGetter != null)
                {
                    return this.AttachedPropertyGetter.Name.Substring("Get".Length);
                }
                else
                {
                    // One of the above should have worked.  If all of them had
                    //  failed, then something has gone wrong.  But we still need
                    //  to be able to provide *something* because a name is
                    //  needed for the exception message.
                    if( _attributeInfo != null )
                    {
                        return _attributeInfo.Name;
                    }
                    else
                    {
                        return "<unknown>";
                    }
                }
            }
        }
 
        internal object DpOrPiOrMi
        {
            get
            {
                return
                    this.DependencyProperty != null ? (object)this.DependencyProperty :
                    this.PropertyInfo != null ? (object)this.PropertyInfo :
                    (object)this.AttachedPropertySetter;
            }
        }
 
        private BamlRecordReader _reader;
        private short _attributeId;
        private BamlAttributeInfoRecord _attributeInfo;
 
        // This field is defined when a DP is available for a property.
        // When DP is defined we do not go after PropertyInfo or AttachedPropertyGetter/Setter
        // unless it was explicitly requested - because of a perf concern.
        private DependencyProperty _dependencyProperty;
    }
}