TemplateBamlRecordReader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Markup / TemplateBamlRecordReader.cs / 1 / TemplateBamlRecordReader.cs

                            /****************************************************************************\ 
*
* File: TemplateBamlRecordReader.cs
*
* Purpose:  Main class to handle reading a Template Baml records from a stream 
*
* History: 
*    11/22/04:   [....]      Created 
*    06/15/05:   [....]     Refactor for new template architecture
* 
* Copyright (C) 2004 by Microsoft Corporation.  All rights reserved.
*
\***************************************************************************/
 
using System;
using System.Xml; 
using System.IO; 
using System.Windows;
using System.Windows.Navigation; 
using System.Text;
using System.Collections;
using System.ComponentModel;
using System.Windows.Controls; 
using System.Windows.Documents;
using System.Windows.Media.Animation; 
using System.Diagnostics; 
using System.Reflection;
using System.Windows.Threading; 
using System.Windows.Data;

using System.Globalization;
using MS.Utility; 
using MS.Internal;
 
namespace System.Windows.Markup 
{
 
    /// 
    /// Reads BAML from a Stream that pertains to Template elements and properties.
    /// This is an internal class
    ///  
    internal class TemplateBamlRecordReader : BamlRecordReader
    { 
 
#region Constructor
 
        /// 
        /// TemplateBamlRecordReader constructor
        /// 
        /// The input BAML stream, if loading from a file 
        /// StartRecord for List of records, if loading from a dictionary
        /// Index Record into list of records to start parsing at 
        /// The parser context 
        /// Reader stack from upper level parser to get
        ///        context for things such as dictionaries and parents.  
        /// list of root objects for the parse
        internal TemplateBamlRecordReader(
            Stream           bamlStream,
            BamlRecord       bamlStartRecord, 
            BamlRecord       bamlIndexRecord,
            ParserContext    parserContext, 
            ParserStack      bamlReaderStack, 
            ArrayList        rootList)
        { 
            Debug.Assert(null != bamlStream || bamlStartRecord != null);
            Debug.Assert(null != parserContext && null != parserContext.XamlTypeMapper);

            // Link this baml record reader to the "parent" reader, so that 
            // we can see its context stack.
            SetPreviousBamlRecordReader( parserContext.BamlReader ); 
 
            ParserContext = parserContext;
            RootList = rootList; 

            PreParsedRecordsStart = bamlStartRecord;
            PreParsedCurrentRecord = bamlIndexRecord;
 
            if (bamlStream != null)
            { 
                BamlStream = bamlStream; 
            }
 
            RootElement = ParserContext.RootElement;
            ComponentConnector = RootElement as IComponentConnector;
            ContextStack = bamlReaderStack;
 
            _elementDepth = 0;
 
            // We're starting out in the template element itself, e.g.  tag?

            if( _inTemplateElement ) 
            {
                // Yes 
                moreData = TryReadTemplateElementRecord( bamlRecord ); 

                // If we're still in the template element itself, ReadRootRecord above is all the processing 
                // we need.

                if (_inTemplateElement)
                { 
                    return moreData;
                } 
 
                // Otherwise, we're on the first child of the root element (the first child of the  tag)
                else 
                {
                    // Put the template's TargetType into the parser context for use by Setter's etc (see comment
                    // on ParserContext.TargetType).
 
                    ParserContext.TargetType = _frameworkTemplate.TargetTypeInternal;
 
                    // Give the template its own copy of the parser context.  It needs a copy, because it's 
                    // going to use it later on every time it's applied.
 
                    _frameworkTemplate.CopyParserContext(ParserContext);

                }
            } 

            // Check to see if we should update _inContent. 
 
            if (_elementDepth == 1 && CurrentContext.ContextType == ReaderFlags.ClrObject)
            { 
                // We're directly under the  tag ...

                if (bamlRecord.RecordType == BamlRecordType.ElementStart)
                { 
                    // ... and we're at a start element, so we must be in template content.
 
                    _inContent = true; 

                    _optimizedTemplateContent.BeginReadingContent(ParserContext); 
                }
                else if( _inContent )
                {
                    // ... but we're not on an element start, and we were in content, 
                    // so we must not be any more.
 
                    _inContent = false; 
                    _optimizedTemplateContent.EndReadingContent();
                } 
            }


            // Are we in the template content? 

            if( _inContent) 
            { 
                // Yes, we're in template content.  We do some minimal amount of
                // processing here, but mostly pass to AddContentRecord. 

                // If this is a map table record (such as an attribute info), process
                // it normally.
 
                if( BamlRecordHelper.IsMapTableRecordType( bamlRecord.RecordType ))
                { 
                    base.ReadRecord(bamlRecord); 
                }
 
                // Simiarly, let base process deferrable content and connection IDs

                else if( bamlRecord.RecordType == BamlRecordType.DeferableContentStart
                         || 
                         bamlRecord.RecordType == BamlRecordType.ConnectionId )
                { 
                    base.ReadRecord(bamlRecord); 
                }
 
                // If this is an element start/end, we have to call the override directly.

                else if( bamlRecord.RecordType == BamlRecordType.ElementStart )
                { 
                    // This is to avoid the checks for injected tags done by the base reader
                    ReadElementStartRecord((BamlElementStartRecord)bamlRecord); 
                } 
                else if( bamlRecord.RecordType == BamlRecordType.ElementEnd )
                { 
                    // This is to avoid the checks for injected tags done by the base reader
                    ReadElementEndRecord(false);
                }
 
                // Otherwise, hand off the record to the OptimizedTemplateContent.
                else 
                { 
                    AddContentRecord( bamlRecord );
                } 
            }

            else
            { 
                // We're not in the content any more, process the triggers.
 
                moreData = ReadNonContentRecord( bamlRecord ); 
            }
 

            _currentBamlRecord = null;

            return _elementDepth > 0 && moreData; 
        }
 
 

        //+----------------------------------------------------------------------- 
        //
        //  ReadRootRecord
        //
        //  Read a baml record that's part of the template tag itself, i.e. 
        //  part of the  element.  Note that this routine
        //  will keep the _inRootElement flag up-to-date, and will *not* process 
        //  the last record, where it discovers that it's out of the root element. 
        //
        //+----------------------------------------------------------------------- 

        internal bool TryReadTemplateElementRecord( BamlRecord bamlRecord )
        {
            bool moreData = true; 
            Debug.Assert( _inTemplateElement );
 
            if( bamlRecord.RecordType == BamlRecordType.ElementStart ) 
            {
                // If this is an element start record, we're either on the 
        //  tag itself, and not part of the template content (i.e. it's either the 
        //  .Resources or the .Triggers). 
        //
        //+------------------------------------------------------------------------------ 

        internal bool ReadNonContentRecord( BamlRecord bamlRecord )
        {
            bool skipRead = false; 

            // Look for the "Value" and "Property" attributes in triggers, setters, and conditions. 
            // We won't really process these until the end of the element. 

            if (bamlRecord.RecordType == BamlRecordType.Property 
                ||
                bamlRecord.RecordType == BamlRecordType.PropertyWithConverter)
            {
                BamlPropertyRecord bamlPropertyRecord = bamlRecord as BamlPropertyRecord; 

                short converterTypeId = 0; 
                BamlPropertyWithConverterRecord bamlPropertyWithConverterRecord = bamlRecord as BamlPropertyWithConverterRecord; 
                if( bamlPropertyWithConverterRecord != null )
                { 
                    converterTypeId = bamlPropertyWithConverterRecord.ConverterTypeId;
                }

 
                // Is this a "Value" property?  If so, see if it's part of a trigger, setter, or
                // condition, and if so save it away. 
 
                string name = MapTable.GetAttributeNameFromId(bamlPropertyRecord.AttributeId);
                if (name == "Value") 
                {
                    if( CurrentContext.ObjectData is Trigger || CurrentContext.ObjectData is DataTrigger )
                    {
                        Debug.Assert( _triggerValueString == null ); 
                        _triggerValueString = bamlPropertyRecord.Value;
                        _triggerValueConverterTypeId = converterTypeId; 
                        skipRead = true; 
                    }
                    else if( CurrentContext.ObjectData is Setter ) 
                    {
                        Debug.Assert( _setterValueString == null );
                        _setterValueString = bamlPropertyRecord.Value;
                        _setterValueConverterTypeId = converterTypeId; 
                        skipRead = true;
                    } 
                    else if( CurrentContext.ObjectData is Condition ) 
                    {
                        Debug.Assert( _conditionValueString == null ); 
                        _conditionValueString = bamlPropertyRecord.Value;
                        _conditionValueConverterTypeId = converterTypeId;
                        skipRead = true;
                    } 
                    else
                    { 
                        // CurrentContext.ObjectData is none of the 
                        //  types above, we need skipRead to stay false
                        //  so we will ask base BamlRecordReader to process the data. 
                    }
                }

                else if (name == "Property") 
                {
 
                    if( CurrentContext.ObjectData is Trigger ) 
                    {
                        Debug.Assert( _triggerPropertyString == null ); 
                        _triggerPropertyString = bamlPropertyRecord.Value;
                        skipRead = true;
                    }
                    else if( CurrentContext.ObjectData is Setter ) 
                    {
                        Debug.Assert( _setterPropertyString == null ); 
                        _setterPropertyString = bamlPropertyRecord.Value; 
                        skipRead = true;
                    } 
                    else if( CurrentContext.ObjectData is Condition )
                    {
                        Debug.Assert( _conditionPropertyString == null );
                        _conditionPropertyString = bamlPropertyRecord.Value; 
                        skipRead = true;
                    } 
                    else 
                    {
                        // CurrentContext.ObjectData is none of the 
                        //  types above, we need skipRead to stay false
                        //  so we will ask base BamlRecordReader to process the data.
                    }
                } 

                else if (name == "SourceName") 
                { 
                    if( CurrentContext.ObjectData is Trigger )
                    { 
                        Debug.Assert( _sourceNameString == null );
                        _sourceNameString = bamlPropertyRecord.Value;
                        skipRead = true;
                    } 
                    else if( CurrentContext.ObjectData is Condition )
                    { 
                        Debug.Assert( _sourceNameString == null ); 
                        _sourceNameString = bamlPropertyRecord.Value;
                        skipRead = true; 
                    }
                }

                /* 
                else if( attrInfo.Name == "TargetName" )
                { 
                    if( CurrentContext.ObjectData is Setter ) 
                    {
                        Debug.Assert( _targetNameString == null ); 
                        _targetNameString = bamlPropertyRecord.Value;
                        skipRead = true;
                    }
                } 
                */
 
            } 

            // If this is the end element of a Trigger, Setter, or Condition, 
            // finish processing of it (convert the Value/Property properties).

            else if (bamlRecord.RecordType == BamlRecordType.ElementEnd)
            { 
                if (CurrentContext.ObjectData != null)
                { 
                    CompleteSetterOrTriggerOrCondition(CurrentContext.ObjectData); 
                }
            } 

            // If we didn't process this record internally above, pass it up to base.
            if (!skipRead)
                return base.ReadRecord(bamlRecord); 
            else
                return true; 
        } 

        protected override void ReadPropertyWithExtensionRecord(BamlPropertyWithExtensionRecord bamlPropertyRecord) 
        {
            string propertyName = MapTable.GetAttributeNameFromId(bamlPropertyRecord.AttributeId);
            object value = GetExtensionValue(bamlPropertyRecord, propertyName);
 
            bool handled = BaseReadOptimizedMarkupExtension(propertyName, value);
            if (!handled) 
            { 
                base.ReadPropertyWithExtensionRecord(bamlPropertyRecord);
            } 
        }

        protected override void ReadPropertyWithStaticResourceIdRecord(
            BamlPropertyWithStaticResourceIdRecord bamlPropertyWithStaticResourceIdRecord) 
        {
            string propertyName = MapTable.GetAttributeNameFromId(bamlPropertyWithStaticResourceIdRecord.AttributeId); 
 
            // Find the StaticResourceValue for the given Id
            object value = GetStaticResourceFromId(bamlPropertyWithStaticResourceIdRecord.StaticResourceId); 

            bool handled = BaseReadOptimizedMarkupExtension(propertyName, value);
            if (!handled)
            { 
                base.ReadPropertyWithStaticResourceIdRecord(bamlPropertyWithStaticResourceIdRecord);
            } 
        } 

        private bool BaseReadOptimizedMarkupExtension(string propertyName, object value) 
        {
            object o = CurrentContext.ObjectData;

            if (propertyName == XamlStyleSerializer.SetterValueAttributeName) 
            {
                Setter setter = o as Setter; 
                if (setter != null) 
                {
                    Debug.Assert(setter.Value == DependencyProperty.UnsetValue); 
                    Debug.Assert(_setterValueObject == DependencyProperty.UnsetValue);
                    _setterValueObject = value;
                    return true;
                } 

                Trigger trigger = o as Trigger; 
                if (trigger != null) 
                {
                    Debug.Assert(trigger.Value == DependencyProperty.UnsetValue); 
                    Debug.Assert(_triggerValueObject == DependencyProperty.UnsetValue);
                    _triggerValueObject = value;
                    return true;
                } 

                Condition condition = o as Condition; 
                if (condition != null) 
                {
                    Debug.Assert(condition.Value == DependencyProperty.UnsetValue); 
                    Debug.Assert(_conditionValueObject == DependencyProperty.UnsetValue);
                    _conditionValueObject = value;
                    return true;
                } 

                DataTrigger dataTrigger = o as DataTrigger; 
                if (dataTrigger != null) 
                {
                    Debug.Assert(dataTrigger.Value == DependencyProperty.UnsetValue); 
                    Debug.Assert(_triggerValueObject == DependencyProperty.UnsetValue);
                    _triggerValueObject = value;
                    return true;
                } 
            }
 
            return false; 
        }
 
        protected override void ReadPropertyCustomRecord(BamlPropertyCustomRecord bamlPropertyRecord)
        {
            object o = CurrentContext.ObjectData;
            string propertyName = MapTable.GetAttributeNameFromId(bamlPropertyRecord.AttributeId); 

            if (propertyName == XamlStyleSerializer.SetterPropertyAttributeName) 
            { 
                DependencyProperty propertyDP = GetCustomDependencyPropertyValue(bamlPropertyRecord);
                Debug.Assert(propertyDP != null); 

                Setter setter = o as Setter;
                if (setter != null)
                { 
                    Debug.Assert(setter.Property == null);
                    setter.Property = propertyDP; 
                    return; 
                }
 
                Trigger trigger = o as Trigger;
                if (trigger != null)
                {
                    Debug.Assert(trigger.Property == null); 
                    trigger.Property = propertyDP;
                    return; 
                } 

                Condition condition = o as Condition; 
                if (condition != null)
                {
                    Debug.Assert(condition.Property == null);
                    condition.Property = propertyDP; 
                    return;
                } 
            } 
            else if (propertyName == XamlStyleSerializer.SetterValueAttributeName)
            { 
                Setter setter = o as Setter;
                if (setter != null)
                {
                    // Setter "Property" property is always set before "Value" property 
                    Debug.Assert(setter.Property != null && setter.Value == DependencyProperty.UnsetValue);
                    setter.Value = GetCustomValue(bamlPropertyRecord, setter.Property.PropertyType, propertyName); 
                    return; 
                }
 
                Trigger trigger = o as Trigger;
                if (trigger != null)
                {
                    // Trigger "Property" property is always set before "Value" property 
                    Debug.Assert(trigger.Property != null && trigger.Value == DependencyProperty.UnsetValue);
                    trigger.Value = GetCustomValue(bamlPropertyRecord, trigger.Property.PropertyType, propertyName); 
                    return; 
                }
 
                Condition condition = o as Condition;
                if (condition != null)
                {
                    // Condition "Property" property is always set before "Value" property 
                    Debug.Assert(condition.Property != null && condition.Value == DependencyProperty.UnsetValue);
                    condition.Value = GetCustomValue(bamlPropertyRecord, condition.Property.PropertyType, propertyName); 
                    return; 
                }
            } 

            base.ReadPropertyCustomRecord(bamlPropertyRecord);
        }
 
        //+-------------------------------------------------------------------------------
        // 
        //  CompleteSetterOrTriggerOrCondition 
        //
        //  This is called when we found the end tag of a Setter, Trigger, or Condition. 
        //  This is where we type-convert the properties that were order-dependent,
        //  e.g. Value property depends on knowing the Property property (so it can find
        //  the right type converter).
        // 
        //+--------------------------------------------------------------------------------
 
        private void CompleteSetterOrTriggerOrCondition(Object o) 
        {
            string nameString; 
            object convertedValue = null;
            DependencyProperty propertyDP = null;

            // Handle setters 
            Setter setter = o as Setter;
 
            if (setter != null) 
            {
                nameString = setter.TargetName;     // do not reset setter.TargetName 
                propertyDP = setter.Property;
                convertedValue = setter.ValueInternal;
                CompletePropertyAndValue(o,
                                         ref nameString, 
                                         ref _setterPropertyString,
                                         ref _setterValueString, 
                                         ref _setterValueObject, 
                                         ref _setterValueConverterTypeId,
                                         ref propertyDP, 
                                         ref convertedValue);

                setter.Property = propertyDP;
                setter.Value = convertedValue; 
                return;
            } 
 
            // Handle triggers
            Trigger trigger = o as Trigger; 

            if (trigger != null)
            {
                trigger.SourceName = _sourceNameString; 
                propertyDP = trigger.Property;
                convertedValue = trigger.Value; 
                CompletePropertyAndValue(o, 
                                         ref _sourceNameString,
                                         ref _triggerPropertyString, 
                                         ref _triggerValueString,
                                         ref _triggerValueObject,
                                         ref _triggerValueConverterTypeId,
                                         ref propertyDP, 
                                         ref convertedValue );
 
                trigger.Property = propertyDP; 
                trigger.Value = convertedValue;
                return; 
            }

            // Handle conditions
            Condition condition = o as Condition; 

            if (condition != null) 
            { 
                condition.SourceName = _sourceNameString;
                propertyDP = condition.Property; 
                convertedValue = condition.Value;
                bool copyDP = true;

                if (_conditionPropertyString == null && propertyDP == null) 
                {
                    // we get here, for example, in a Condition for a MultiDataTrigger. 
                    // This has no Property, but we should still convert the Value 
                    // to an object, including resolving MarkupExtensions, freezing, etc.
                    propertyDP = ContentPresenter.ContentProperty;  // any DP of type Object will do 
                    copyDP = false;
                }

                CompletePropertyAndValue(o, 
                                         ref _sourceNameString,
                                         ref _conditionPropertyString, 
                                         ref _conditionValueString, 
                                         ref _conditionValueObject,
                                         ref _conditionValueConverterTypeId, 
                                         ref propertyDP,
                                         ref convertedValue);

                if (copyDP) 
                    condition.Property = propertyDP;
                condition.Value = convertedValue; 
                return; 
            }
 
            // Handle data triggers
            DataTrigger dataTrigger = o as DataTrigger;

            if (dataTrigger != null) 
            {
                nameString = null;                              // DataTrigger does not use named elements 
                convertedValue = dataTrigger.Value; 
                propertyDP = ContentPresenter.ContentProperty;  // any DP of type Object will do
                CompletePropertyAndValue(o, 
                                         ref nameString,
                                         ref _triggerPropertyString,
                                         ref _triggerValueString,
                                         ref _triggerValueObject, 
                                         ref _triggerValueConverterTypeId,
                                         ref propertyDP, 
                                         ref convertedValue); 

                dataTrigger.Value = convertedValue; 
                return;
            }
        }
 

        //+------------------------------------------------------------------------- 
        // 
        //  CompletePropertyAndValue
        // 
        //  As part of completing the Setter, Trigger, or Condition element,
        //  figure out the property and/or value properties.
        //
        //+------------------------------------------------------------------------- 

        private void CompletePropertyAndValue(object targetObject, 
                                              ref string targetName, 
                                              ref string propertyString,
                                              ref string valueString, 
                                              ref object valueObject,
                                              ref short valueConverterTypeId,
                                              ref DependencyProperty propertyDP,
                                              ref object convertedValue) 
        {
            if (propertyDP == null) 
            { 
                if (propertyString == null)
                { 
                    ThrowException(SRID.StylePropertySetterMinAttrs);
                }

                // Get the owner type 

                Type ownerType = FindTypeToUseForResolvingProperty( targetName ); 
 
                // Convert the property string to a DP
 
                propertyDP = XamlTypeMapper.ParsePropertyName(ParserContext, propertyString, ref ownerType);

                if (propertyDP == null)
                { 
                    ThrowException(SRID.ParserNoDPOnOwner, propertyString, ownerType.FullName);
                } 
            } 

            targetName = null; 
            propertyString = null;

            // Convert the value string to a value.
 
            if (valueString != null)
            { 
                Debug.Assert(DependencyProperty.UnsetValue == convertedValue); 
                // Yes, convert the value from string
 
                TypeConvertContext typeConverterContext = new TypeConvertContext(ParserContext);

                convertedValue = XamlTypeMapper.ParseProperty(
                                             targetObject, 
                                             propertyDP.PropertyType,
                                             propertyDP.Name, 
                                             propertyDP, 
                                             typeConverterContext,
                                             ParserContext, 
                                             valueString,
                                             valueConverterTypeId);
            }
            else if (DependencyProperty.UnsetValue != valueObject) 
            {
                convertedValue = valueObject; 
            } 
            else if (DependencyProperty.UnsetValue == convertedValue)
            { 
                ThrowException(SRID.StylePropertySetterMinAttrs);
            }

            // Clear all the data holding members 

            valueString = null; 
            valueObject = DependencyProperty.UnsetValue; 
            valueConverterTypeId = 0;
 
            // This value will be shared by all instances of the template.  So freeze it,
            // call ME.ProvideValue on it, etc.

            StyleHelper.ProcessSharedPropertyValue( 
                    ParserContext,
                    targetObject, 
                    propertyDP, 
                    ref convertedValue );
        } 



 
        //+---------------------------------------------------------------------------------
        // 
        //  FindTypeToUseForResolvingProperty 
        //
        //  When processing the Property property of a Condition/Setter/Trigger, 
        //  we need to know the owner type, so that we can look up the property by name.
        //
        //+----------------------------------------------------------------------------------
 
        private Type FindTypeToUseForResolvingProperty(string targetName)
        { 
            // When parsing a CLR property, the type to use is current TypeTag's type, if 
            // there is one, or the type refered to by the Target="SomeID" reference.
            // The types of the ID reference are held in the _templateNameToType table. 

            Type type = null;

            // Do we have a target name? 

            if (targetName != null) 
            { 
                // Yes.  Get the target's type, which we cached away while reading the content.
 
                type = (Type)_templateNameToType[targetName];
                if (type == null)
                {
                    ThrowException(SRID.TemplateNoTarget, targetName); 
                }
            } 
 
            // If we don't have an owner type yet, use the one for the
            // target type of the Template. 

            else
            {
                type = _frameworkTemplate.TargetTypeInternal; 
            }
 
            return type; 

        } 


        /***************************************************************************\
        * 
        * TemplateBamlRecordReader.ReadElementStartRecord
        * 
        * Read the start of an element.  This is used to track element depth, so 
        * this reader knows when to stop reading the template section.
        * 
        \***************************************************************************/

        protected override bool ReadElementStartRecord(
            BamlElementStartRecord bamlElementStartRecord) 
        {
            bool usedSerializer = false; 
 
            _elementDepth++;
 
            if( _inContent )
            {
                _lastElementTypeId = bamlElementStartRecord.TypeId;
 
                AddContentRecord( bamlElementStartRecord );
            } 
            else 
            {
                usedSerializer = base.ReadElementStartRecord( bamlElementStartRecord ); 
                if( usedSerializer )
                {
                    --_elementDepth;
                } 
            }
 
            return usedSerializer; 

        } 

        protected override void ReadConnectionId(BamlConnectionIdRecord bamlConnectionIdRecord)
        {
            if( _inContent ) 
            {
                AddContentRecord( bamlConnectionIdRecord ); 
            } 
            else
            { 
                base.ReadConnectionId( bamlConnectionIdRecord );
            }

            return; 

        } 
 

 

        /****************************************************************************\
        *
        * TemplateBamlRecordReader.ReadElementEndRecord 
        *
        * Called when parsing the end of an Element.  When the end of the Template 
        * is reached, finish parsing the template block by setting the record 
        * collection on the template.
        * 
        \***************************************************************************/


        protected internal override void ReadElementEndRecord(bool fromNestedBamlRecordReader) 
        {
            // Is this from a nested reader (e.g. a nested style or template)? 
            if( fromNestedBamlRecordReader ) 
            {
                // If we're in the template content, then do nothing.  If we aren't 
                // in the content, then just pass up the call to base.

                if (!_inContent)
                { 
                    base.ReadElementEndRecord(fromNestedBamlRecordReader);
                } 
 
                return;
            } 


            _elementDepth--;
 

            // Are we somewhere other than the end of the template? 
 
            if( _elementDepth != 0 )
            { 
                // If we're in content, just collect the record.
                if( _inContent )
                {
                    AddContentRecord(_currentBamlRecord); 
                }
 
                // If we're not in content, process normally 
                else
                { 
                    base.ReadElementEndRecord( fromNestedBamlRecordReader );
                }
            }
 
            // Otherwise, we're at the end of the template itself
 
            else 
            {
                // Put the shared Baml content records into the template. 

                // For some reason, setting the ParserContext causes it to update the BamlRecordReader
                // to point to it.  So update that reference here.
                ParserContext = ParserContext; 

                // We don't need to keep the baml records any more; the template has 
                // kept the ones it needs. 

                _templateNameToType = null; 

                // The template is done parsing, so call back to the base to have the style added
                // to the parent element, or to a resources dictionary.  Check to see if we need
                // to generate a dictionary key at this point.  If it has not been assigned, then 
                // do it now.
                if (GetDictionaryFromContext(ParentContext, true /*isInjected*/ ) != null && CurrentContext.Key == null) 
                { 
                    // We use a DataTemplateKey or TableTemplateKey object as
                    // the key if we have a DataType property set on the template. 
                    object key = null;
                    if (_frameworkTemplate != null)
                    {
                        if (_frameworkTemplate.DataTypeInternal != null) 
                        {
                            key = new DataTemplateKey(_frameworkTemplate.DataTypeInternal); 
                        } 
                    }
 
                    if (key != null)
                    {
                        CurrentContext.Key = key;
                    } 
                }
 
                // Process the end record itself 
                PreviousBamlRecordReader.ReadElementEndRecord(true);
 
                // Put back the old reader into the ParserContext
                ParserContext.BamlReader = PreviousBamlRecordReader;

 
            }
        } 
 
        /****************************************************************************\
        * 
        * TemplateBamlRecordReader.ReadDeferableContentStart
        *
        * Called when parsing the deferable content start element.
        * For the case of a ResourceDictionary inside template content, we read 
        * the dictionary values into a byte array while creating the template
        * content. Later during template instantiation when the dictionary instance 
        * is created we use this buffer to create a memory stream so that the 
        * ResourceDictionary can use it to RealizeDeferredContent. This is required
        * because at template instantiation time we do not have a stream to work with. 
        * The reader operates on a linked list of BamlRecords instead.
        *
        \***************************************************************************/
 
        internal override void ReadDeferableContentStart(
            BamlDeferableContentStartRecord bamlDeferableContentStartRecord) 
        { 
            if (!_inContent)
            { 
                    base.ReadDeferableContentStart( bamlDeferableContentStartRecord );
                    return;
            }
 
            AddContentRecord(bamlDeferableContentStartRecord);
 
            Stream stream = null; 
            long startPosition = -1;
 
            if (PreParsedRecordsStart == null)
            {
                stream = BinaryReader.BaseStream;
                startPosition = stream.Position; 
            }
 
            // Read past all the keys and staticresources belonging to this deferred section 

            BamlRecord      bamlRecord; 
            BamlRecordType  nextType = GetNextRecordType();

            while (nextType == BamlRecordType.DefAttributeKeyString ||
                   nextType == BamlRecordType.DefAttributeKeyType || 
                   nextType == BamlRecordType.KeyElementStart)
            { 
                bamlRecord = GetNextRecord(); 
                ReadRecord(bamlRecord);
 
                if (nextType == BamlRecordType.KeyElementStart)
                {
                    while (nextType != BamlRecordType.KeyElementEnd)
                    { 
                        bamlRecord = GetNextRecord();
                        ReadRecord(bamlRecord); 
 
                        nextType = bamlRecord.RecordType;
 
                    }
                }

                nextType = GetNextRecordType(); 

                while (nextType == BamlRecordType.StaticResourceStart || 
                       nextType == BamlRecordType.StaticResourceId || 
                       nextType == BamlRecordType.OptimizedStaticResource)
                { 
                    bamlRecord = GetNextRecord();
                    ReadRecord(bamlRecord);

                    if (nextType == BamlRecordType.StaticResourceStart) 
                    {
                        while (nextType != BamlRecordType.StaticResourceEnd) 
                        { 
                            bamlRecord = GetNextRecord();
                            ReadRecord(bamlRecord); 

                            nextType = bamlRecord.RecordType;
                        }
                    } 

                    nextType = GetNextRecordType(); 
                } 

                nextType = GetNextRecordType(); 
            }

            if (PreParsedRecordsStart == null)
            { 
                // Copy the defer load contents into a buffer.
 
                long  endOfKeysPosition = stream.Position; 
                Int32 valuesSize = (Int32)(bamlDeferableContentStartRecord.ContentSize - endOfKeysPosition + startPosition);
 
                byte[] buffer = new byte[valuesSize];
                if (valuesSize > 0)
                {
                    MS.Internal.IO.Packaging.PackagingUtilities.ReliableRead( 
                        BinaryReader, buffer, 0, valuesSize);
                } 
 
                // Cache the values buffer on the DeferableContentRecord so that it
                // can then be retrieved and used during template instantiation. 

                bamlDeferableContentStartRecord.ValuesBuffer = buffer;
            }
 
        }
 
#endregion // Overrides 

 
        /***************************************************************************\
        *
        * AddContentRecord
        * 
        * Add a new baml record to the collection of records to be held by the
        * template. 
        * 
        \***************************************************************************/
 

        private void AddContentRecord(BamlRecord bamlRecord )
        {
            // If this is a BamlElementStartRecord, convert it into a 
            // BamlNamedElementStartRecord, as this is what the template
            // infrastructure is based on.  We have to do it here, so that 
            // it is incorporated correctly into the linked list below. 

            bamlRecord = CreateNameRecordIfNecessary( bamlRecord ); 

            // Link the baml records together.  We need them linked so that we
            // can call nested custom serializers, and also for unwinding when we
            // discover an un-shareable property value. 

            if (_bamlRecordListTail != null  ) 
            { 
                _bamlRecordListTail.Next = bamlRecord;
            } 

            // Pin the record so we can store it on this list.
            bamlRecord.Pin();
 
            // Also Pin any Debug extension record.
            BamlRecord debugExtensionRecord=null; 
            if (BamlRecordHelper.HasDebugExtensionRecord(ParserContext.IsDebugBamlStream, bamlRecord)) 
            {
                debugExtensionRecord = bamlRecord.Next; 
                debugExtensionRecord.Pin();
            }

            // For named elements, keep track of the type of the element.  We need this to 
            // resolve property references in triggers.
 
            if( bamlRecord.RecordType == BamlRecordType.Property 
                ||
                bamlRecord.RecordType == BamlRecordType.PropertyWithConverter ) 
            {
                BamlPropertyRecord bamlPropertyRecord = bamlRecord as BamlPropertyRecord;

                if (MapTable.DoesAttributeMatch(bamlPropertyRecord.AttributeId, BamlAttributeUsage.RuntimeName)) 
                {
                    // (Could search the baml records here instead) 
                    _templateNameToType[bamlPropertyRecord.Value] = MapTable.GetTypeFromId( _lastElementTypeId ); 
                }
            } 

            _optimizedTemplateContent.AddContentRecord( bamlRecord );

            // Advance the tail (including any Debug Extension record) 
            _bamlRecordListTail = (debugExtensionRecord == null) ? bamlRecord : debugExtensionRecord;
        } 
 

        /****************************************************************************\ 
        *
        * CreateNameRecordIfNecessary
        *
        * This method converts a BamlElementStart record into a 
        * BamlNamedElementStartRecord.  See the comment on BamlNamedElementStartRecord
        * for more detail on that record. 
        * 
        \***************************************************************************/
 
        private BamlRecord CreateNameRecordIfNecessary( BamlRecord bamlRecord )
        {
            // If this isn't a BamlElementStart record, then we don't need to do anything.
 
            if( bamlRecord.GetType() != typeof(BamlElementStartRecord) )
            { 
                return bamlRecord; 
            }
 
            BamlElementStartRecord bamlElementStartRecord = (BamlElementStartRecord)bamlRecord;

            // Or if it's already a BamlNamedElementStartRecord, then we're similarly done.
 
            if( bamlElementStartRecord is BamlNamedElementStartRecord )
            { 
                return bamlRecord; 
            }
 
            // Convert this BamlElementStartRecord into a BamlNamedElementStartRecord

            BamlNamedElementStartRecord bamlNamedElementStartRecord = new BamlNamedElementStartRecord();
            bamlNamedElementStartRecord.PinnedCount = bamlElementStartRecord.PinnedCount; 
            bamlNamedElementStartRecord.TypeId = bamlElementStartRecord.TypeId;
            bamlNamedElementStartRecord.Next = bamlElementStartRecord.Next; 
            bamlNamedElementStartRecord.CreateUsingTypeConverter = bamlElementStartRecord.CreateUsingTypeConverter; 
            bamlNamedElementStartRecord.IsInjected = bamlElementStartRecord.IsInjected;
 
            bamlElementStartRecord.Next = null;

            return bamlNamedElementStartRecord;
 
        }
 
 

 
        //+-----------------------------------------------------------------------------------------
        //
        //  State
        // 
        //+-----------------------------------------------------------------------------------------
 
        short                       _lastElementTypeId; 

        private int                         _elementDepth; 
        private FrameworkTemplate           _frameworkTemplate;
        private OptimizedTemplateContent    _optimizedTemplateContent;
        private bool                        _inTemplateElement;
        private bool                        _inContent; 

        private string             _triggerValueString; 
        private object             _triggerValueObject = DependencyProperty.UnsetValue; 
        private short              _triggerValueConverterTypeId;
        private string             _triggerPropertyString; 

        private string             _setterValueString;
        private object             _setterValueObject = DependencyProperty.UnsetValue;
        private short              _setterValueConverterTypeId; 
        private string             _setterPropertyString;
 
        private string             _conditionValueString; 
        private object             _conditionValueObject = DependencyProperty.UnsetValue;
        private short              _conditionValueConverterTypeId; 
        private string             _conditionPropertyString;


        private string             _sourceNameString; 

        private Hashtable          _templateNameToType = new Hashtable(); 
        private BamlRecord         _bamlRecordListTail; 

        private BamlRecord         _currentBamlRecord; 

    }

} 


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

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK