TemplateBamlRecordReader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / 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:   varsham      Created 
*    06/15/05:   peterost     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)
            { 
                // If this a nested template then it needs a separate set of BamlRecords
                // that can be chained together to represent the template content.

                if (_inNestedTemplate) 
                {
                    bamlRecord = BamlRecordManager.CloneRecord(bamlRecord); 
                    _currentBamlRecord = bamlRecord; 
                }
 
                // 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)) 
            {
                // If this a nested template then it needs a separate set of BamlRecords
                // that can be chained together to represent the template content.
 
                if (_inNestedTemplate)
                { 
                    debugExtensionRecord = BamlRecordManager.CloneRecord(bamlRecord.Next); 
                    bamlRecord.Next = debugExtensionRecord;
                } 
                else
                {
                    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;
 
        }

        private bool InNestedTemplate()
        { 
            BamlRecordReader reader = PreviousBamlRecordReader;
 
            while (reader != null) 
            {
                if (reader is TemplateApplicationHelper) 
                {
                    return true;
                }
 
                reader = reader.PreviousBamlRecordReader;
            } 
 
            return false;
        } 



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

        private int                         _elementDepth;
        private FrameworkTemplate           _frameworkTemplate; 
        private OptimizedTemplateContent    _optimizedTemplateContent;
        private bool                        _inTemplateElement; 
        private bool                        _inContent; 
        private bool                        _inNestedTemplate;
 
        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.
/****************************************************************************\ 
*
* File: TemplateBamlRecordReader.cs
*
* Purpose:  Main class to handle reading a Template Baml records from a stream 
*
* History: 
*    11/22/04:   varsham      Created 
*    06/15/05:   peterost     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)
            { 
                // If this a nested template then it needs a separate set of BamlRecords
                // that can be chained together to represent the template content.

                if (_inNestedTemplate) 
                {
                    bamlRecord = BamlRecordManager.CloneRecord(bamlRecord); 
                    _currentBamlRecord = bamlRecord; 
                }
 
                // 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)) 
            {
                // If this a nested template then it needs a separate set of BamlRecords
                // that can be chained together to represent the template content.
 
                if (_inNestedTemplate)
                { 
                    debugExtensionRecord = BamlRecordManager.CloneRecord(bamlRecord.Next); 
                    bamlRecord.Next = debugExtensionRecord;
                } 
                else
                {
                    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;
 
        }

        private bool InNestedTemplate()
        { 
            BamlRecordReader reader = PreviousBamlRecordReader;
 
            while (reader != null) 
            {
                if (reader is TemplateApplicationHelper) 
                {
                    return true;
                }
 
                reader = reader.PreviousBamlRecordReader;
            } 
 
            return false;
        } 



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

        private int                         _elementDepth;
        private FrameworkTemplate           _frameworkTemplate; 
        private OptimizedTemplateContent    _optimizedTemplateContent;
        private bool                        _inTemplateElement; 
        private bool                        _inContent; 
        private bool                        _inNestedTemplate;
 
        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