OptimizedTemplateContent.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Markup / OptimizedTemplateContent.cs / 1 / OptimizedTemplateContent.cs

                            /****************************************************************************\ 
*
* File:     OptimizedTemplateContent.cs
*
* Purpose:  Represents a FrameworkTemplate's content 
*           in an optimized form (separates the shareable parts of the
*           template from those which need to be re-instantiated on 
*           every use). 
*
* Copyright (C) 2005 by Microsoft Corporation.  All rights reserved. 
*
\***************************************************************************/

using System; 
using System.Xml;
using System.IO; 
using System.Windows; 
using System.Windows.Media;
using System.Windows.Navigation; 
using System.Text;
using System.Collections;
using System.Collections.Generic;
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.Collections.ObjectModel;
using System.Collections.Specialized; 

 
using System.Globalization; 
using MS.Utility;
 
namespace System.Windows.Markup
{

        /***************************************************************************\ 
        *
        * ShareableRecordState 
        * 
        * States in the sealing state machine.  Used to identify what we are currently
        * processing in ReadRecord. 
        *
        \***************************************************************************/

        internal enum ShareableRecordState 
        {
            // Initial state, or we don't know what the next state will be 
            Unset, 

            // The current record is unshareable and should be added to the unshareable list 
            UnshareableRecord,

            // We are currently within an unshareable subtree.  We will exit this subtree
            // by watching the depth of complex property tags.  All records in an 
            // unshareable subtree go into the unshared list
            UnshareableSubtree, 
 
            // The current record is a shareable dependency property, and should be added
            // to the list of shared properties 
            ShareableRecord,

            // Starting the instantiation of a possibly shared subtree under a complex
            // property.  This may end up being an unshared tree if certain conditions 
            // are encountered.
            StartShareableTree, 
 
            // In the process of building a possibly shared subtree under a complex
            // dependency property. 
            BuildingShareableTree,
        }

        /***************************************************************************\ 
        *
        * BamlSubtreeState 
        * 
        * Used by the OptimizedTemplateContentHelper to tell the OptimizedTemplateContent
        * the outcome of processing the last baml record.  This can in turn be used 
        * to modify the current ShareableRecordState.
        *
        \***************************************************************************/
 
        internal enum BamlSubtreeState
        { 
            // Record or state encountered which means the subtree can't be shared 
            NotShareable,
 
            // Successful end of a subtree that can be shared has been reached
            EndShareableSubtree,

            // Continuing to build subtree.  So far, so good. 
            ContinueShareableSubtree,
        } 
 

    internal class OptimizedTemplateContent 
    {

#region Constructor
 
        internal OptimizedTemplateContent(
            FrameworkTemplate   frameworkTemplate ) 
        { 
            _frameworkTemplate          = frameworkTemplate;
 
            _currentState               = ShareableRecordState.Unset;
            _searchingForName           = false;
            _sharedProperties           = null;
            _unsharedContentCollection  = null; 
            _unsharedContent            = null;
 
        } 

#endregion Constructor 

#region Internals

 
        //+-------------------------------------------------------------------
        // 
        //  BeginReadingContent 
        //
        //  Called by the TemplateBamlRecordReader before it starts reading 
        //  the content portion of the template.  After this, call AddContentRecord
        //  multiple times, then EndReadingContent.
        //
        //+-------------------------------------------------------------------- 

        internal void BeginReadingContent( ParserContext parserContext ) 
        { 
            // We shouldn't have been here before
 
            Debug.Assert( _unsharedContent == null );


            // Keep a copy of the parser context until EndReadingContent 

            _parserContext = parserContext; 
 
            // Initialize all the temporary buffers we need
 
            Debug.Assert( _sharedProperties == null );
            _sharedProperties         = new FrugalObjectList(16);

            Debug.Assert( _unsharedContentCollection == null ); 
            _unsharedContentCollection = new Collection();
 
            Debug.Assert( _optimizableElementState == null ); 
            _optimizableElementState = new Stack();
 
            Debug.Assert( _optimizedTemplateContentHelper == null );
            _optimizedTemplateContentHelper = new OptimizedTemplateContentHelper( parserContext );

            Debug.Assert( _nameStack == null ); 
            _nameStack = new Stack();
 
        } 

 
        //+-------------------------------------------------------------------
        //
        //  AddContentRecord
        // 
        //  Called by the TemplateBamlRecordReader when it is reading the content
        //  portion of the template.  Call BeginReadingContent before this, and 
        //  EndReadingContent afterwards. 
        //
        //+-------------------------------------------------------------------- 

        internal void AddContentRecord(BamlRecord bamlRecord )
        {
            if( _rootType == null ) 
            {
                BamlElementStartRecord bamlElementStartRecord = bamlRecord as BamlElementStartRecord; 
                _rootType = MapTable.GetTypeFromId(bamlElementStartRecord.TypeId); 
            }
 
            ReadRecord( bamlRecord );
        }

        internal void AddBamlRecordToUnsharedContentCollection(BamlRecord bamlRecord) 
        {
            _unsharedContentCollection.Add(bamlRecord); 
 
            // if this record has a Debug extension in it's Next field than install that also.
            if (BamlRecordHelper.HasDebugExtensionRecord(_parserContext.IsDebugBamlStream, bamlRecord)) 
            {
                _unsharedContentCollection.Add(bamlRecord.Next);
            }
        } 

 
        //+-------------------------------------------------------------------- 
        //
        //  EndReadingContent 
        //
        //  Called by the TemplateBamlRecordReader after it's read all the content.
        //
        //+------------------------------------------------------------------- 

        internal void EndReadingContent() 
        { 
            // Prefetch the values for static resources within the template content
 
            _frameworkTemplate.StaticResourceValues = PrefetchStaticResourceValues();

            // Link all of the unshareable content (that's how we walk through it
            // when instantiating). 

            for( int i = 0; i < _unsharedContentCollection.Count-1; i++ ) 
            { 
                _unsharedContentCollection[i].Next = _unsharedContentCollection[i+1];
            } 

            if( _unsharedContentCollection.Count > 0 )
            {
                _unsharedContentCollection[_unsharedContentCollection.Count-1].Next = null; 
            }
 
            // We're done processing the records, so we're done with 
            // the parser context and the helper objects.
 
            _typeConvertContext = null; // (From the parser context)
            _parserContext = null;

            _optimizedTemplateContentHelper = null; 
            _optimizableElementState = null;
            _nameStack = null; 
 

            #if DEBUG 
            for (int j = 0; j < _unsharedContentCollection.Count; j++)
            {
                Debug.Assert( _unsharedContentCollection[j].IsPinned );
            } 
            #endif
 
            // Since the records are linked, we can just hold on to the first 
            // record, and free the list.
 
            Debug.Assert( _unsharedContent == null );
            _unsharedContent = _unsharedContentCollection[0];
            _unsharedContentCollection = null;
 
            // Another thing we could potentially do here is process the shared values,
            // actually update the tables like StyleHelper.ProcessTemplateContent, 
            // instead of waiting for the template to be sealed.  That's more complicated 
            // code, though, and doesn't appear to be a benefit.
 
        }

        //+--------------------------------------------------------------------------
        // 
        //  PrefetchStaticResourceValues
        // 
        //  Prefetch the staticresource values wrt to the context available at 
        //  template creation time.
        // 
        //+-------------------------------------------------------------------------
        private object[] PrefetchStaticResourceValues()
        {
            object[] staticResourceValues = null; 

            if (_parserContext.InDeferredSection) 
            { 
                // Example:
                // 
                // 
                //     
                // 

                // If we are within deferred section all we need to
                // do is re-resolve the front loaded static resources 

                staticResourceValues = _parserContext.StaticResourcesStack[_parserContext.StaticResourcesStack.Count - 1]; 
 
                // Find the indices of the first and the last StaticResourceId
                // occuring within this template content. In above example this 
                // would be indices 1 - 2.

                short startId = -1;
                short endId = -1; 

                for ( int i = 0; i < _unsharedContentCollection.Count; i++ ) 
                { 
                    BamlRecord bamlRecord = _unsharedContentCollection[i];
                    BamlRecordType recordType = bamlRecord.RecordType; 

                    if (recordType == BamlRecordType.StaticResourceId ||
                        recordType == BamlRecordType.PropertyWithStaticResourceId)
                    { 
                        endId = ((BamlStaticResourceIdRecord)bamlRecord).StaticResourceId;
 
                        if (startId == -1) 
                        {
                            startId = endId; 
                        }
                    }
                }
 
                // Re-resolve the staticresources that belong to this template content and
                // fallback to the pre-fetched value if not resolved within the current context. 
 
                if (startId >= 0)
                { 
                    Debug.Assert(endId >= 0 && endId >= startId && endId < staticResourceValues.Length);

                    for ( int i = startId; i <= endId; i++ )
                    { 
                        // Note that we do not want to search the app or theme because this is
                        // only a re-resolution within the current context stack. The top-level 
                        // deferred section is the only case when we lookup the app and theme 
                        // dictionaries.
 
                        object value = _parserContext.BamlReader.FindResourceInParserStack(
                            ((DeferredResourceReference)staticResourceValues[i]).Key,
                            true /*allowDeferredResourceReference*/,
                            true /*mustReturnDeferredResourceReference*/); 

                        if (value != DependencyProperty.UnsetValue) 
                        { 
                            // If the resource was found replace the existing
                            // entry in the list of pre-fetched values 

                            staticResourceValues[i] = value;
                        }
                    } 
                }
            } 
            else 
            {
                // Example: 
                //
                // 
 
                // Find all the StaticResource records in the unshareable content
 
                // Notice that in the above scenario we only care about the static resources 
                // in the template content and the front-loaded static resources within the
                // deferable content. The StaticResourcesIds need not be altered. 

                ArrayList staticResourceValuesList = null;
                BamlRecordReader bamlReader = null;
 
                for ( int i = 0; i < _unsharedContentCollection.Count; i++ )
                { 
                    // Look for a StaticResource ElementStart record 

                    BamlRecord bamlRecord = _unsharedContentCollection[i]; 
                    BamlRecordType recordType = bamlRecord.RecordType;

                    if (recordType == BamlRecordType.ElementStart ||
                        recordType == BamlRecordType.StaticResourceStart) 
                    {
                        int positiveTypeId = -((BamlElementStartRecord)bamlRecord).TypeId; 
                        if (positiveTypeId == (int)KnownElements.StaticResourceExtension) 
                        {
                            // Find the StaticResource ElementEnd record 

                            int         elementDepth = 1;
                            BamlRecord  srStartRecord = bamlRecord;
 
                            do
                            { 
                                // Keep removing the baml records that belong to the current 
                                // static resource from the unshared list
 
                                _unsharedContentCollection.RemoveAt(i);

                                // Link records in the current static resource together
 
                                bamlRecord.Next = _unsharedContentCollection[i];
 
                                bamlRecord = _unsharedContentCollection[i]; 
                                recordType = bamlRecord.RecordType;
 
                                if (recordType == BamlRecordType.ElementStart ||
                                    recordType == BamlRecordType.StaticResourceStart)
                                {
                                    elementDepth++; 
                                }
                                else if (recordType == BamlRecordType.ElementEnd || 
                                        recordType == BamlRecordType.StaticResourceEnd) 
                                {
                                    elementDepth--; 
                                }

                            } while (elementDepth > 0);
 
                            _unsharedContentCollection.RemoveAt(i);
                            bamlRecord.Next = null; 
 
                            // Ensure that we have a BamlReader and a StaticResourceValuesList
                            EnsureBamlReaderAndStaticResourceValuesList(ref staticResourceValuesList, ref bamlReader); 

                            // Load the StaticResource records
                            bamlReader.PreParsedRecordsStart = srStartRecord;
                            bamlReader.PreParsedCurrentRecord = srStartRecord; 
                            bamlReader.Read();
                            StaticResourceExtension staticResource = (StaticResourceExtension)bamlReader.RootList[0]; 
                            bamlReader.RootList.Clear(); 

                            // Resolve the StaticResource value including lookup to the app and the theme 

                            DeferredResourceReference value = (DeferredResourceReference)bamlReader.PreviousBamlRecordReader.FindResourceInParentChain(
                                staticResource.ResourceKey,
                                true /*allowDeferredResourceReference*/, 
                                true /*mustReturnDeferredResourceReference*/);
 
                            // Add the resolved value to the static resource list 

                            staticResourceValuesList.Add(value); 

                            // Replace the static resource records in this unshared
                            // list with a StaticResourceIdRecord.
 
                            BamlStaticResourceIdRecord bamlStaticResourceIdRecord = new BamlStaticResourceIdRecord();
                            bamlStaticResourceIdRecord.StaticResourceId = (short)(staticResourceValuesList.Count - 1); 
                            bamlStaticResourceIdRecord.Pin(); 

                            _unsharedContentCollection.Insert(i, bamlStaticResourceIdRecord); 
                        }
                    }
                    else if (recordType == BamlRecordType.PropertyWithExtension ||
                             recordType == BamlRecordType.OptimizedStaticResource) 
                    {
                        IOptimizedMarkupExtension optimizedMarkupExtensionRecord = (IOptimizedMarkupExtension)bamlRecord; 
                        int positiveTypeId = optimizedMarkupExtensionRecord.ExtensionTypeId; 
                        if (positiveTypeId == (int)KnownElements.StaticResourceExtension)
                        { 
                            // Remove the baml record with the StaticResource
                            // from the unshared list

                            _unsharedContentCollection.RemoveAt(i); 
                            bamlRecord.Next = null;
 
                            // Ensure that we have a BamlReader and a StaticResourceValuesList 
                            EnsureBamlReaderAndStaticResourceValuesList(ref staticResourceValuesList, ref bamlReader);
 
                            // Load the StaticResource
                            StaticResourceExtension staticResource = (StaticResourceExtension)bamlReader.GetExtensionValue(optimizedMarkupExtensionRecord, null);

                            // Resolve the StaticResource value including lookup to the app and the theme 

                            DeferredResourceReference value = (DeferredResourceReference)bamlReader.PreviousBamlRecordReader.FindResourceInParentChain( 
                                staticResource.ResourceKey, 
                                true /*allowDeferredResourceReference*/,
                                true /*mustReturnDeferredResourceReference*/); 

                            // Add the resolved value to the static resource list

                            staticResourceValuesList.Add(value); 

                            BamlStaticResourceIdRecord bamlStaticResourceIdRecord; 
                            if (recordType == BamlRecordType.PropertyWithExtension) 
                            {
                                // Replace the PropertyWithExtensionRecord in this unshared 
                                // list with a PropertyWithStaticResourceIdRecord.

                                BamlPropertyWithStaticResourceIdRecord bamlPropertyWithStaticResourceIdRecord = new BamlPropertyWithStaticResourceIdRecord();
                                bamlPropertyWithStaticResourceIdRecord.AttributeId = ((BamlPropertyWithExtensionRecord)bamlRecord).AttributeId; 
                                bamlStaticResourceIdRecord = bamlPropertyWithStaticResourceIdRecord;
                            } 
                            else 
                            {
                                // Replace the OptimizedStaticResourceRecord in this unshared 
                                // list with a StaticResourceIdRecord.

                                bamlStaticResourceIdRecord = new BamlStaticResourceIdRecord();
                            } 

                            bamlStaticResourceIdRecord.StaticResourceId = (short)(staticResourceValuesList.Count - 1); 
                            bamlStaticResourceIdRecord.Pin(); 

                            _unsharedContentCollection.Insert(i, bamlStaticResourceIdRecord); 
                        }
                    }
                }
 
                if (staticResourceValuesList != null)
                { 
                    // Restore the reader on the ParserContext 

                    _parserContext.BamlReader = bamlReader.PreviousBamlRecordReader; 

                    staticResourceValues = staticResourceValuesList.ToArray();
                }
            } 

            return staticResourceValues; 
        } 

        //+------------------------------------------------------------------------- 
        //
        //  EnsureBamlReaderAndStaticResourceValuesList
        //
        //  Ensure that we have a BamlReader and a StaticResourceCaluesList to work with 
        //
        //+------------------------------------------------------------------------- 
        private void  EnsureBamlReaderAndStaticResourceValuesList( 
            ref ArrayList        staticResourceValuesList,
            ref BamlRecordReader bamlReader) 
        {
            if (staticResourceValuesList == null)
            {
                // This is the first StaticResource we found 
                // within the template content section
 
                staticResourceValuesList = new ArrayList(); 

                bamlReader = new BamlRecordReader(); 
                bamlReader.SetPreviousBamlRecordReader(_parserContext.BamlReader);
                bamlReader.ParserContext = _parserContext;
                bamlReader.RootList = new ArrayList(1);
            } 
        }
 
        //+-------------------------------------------------------------------------- 
        //
        //  ReadRecord 
        //
        //  Read a single record and process it.  A record is added to the
        //  _unsharedContentCollection, or the value is added to _sharedProperties.
        // 
        //+-------------------------------------------------------------------------
 
        private void ReadRecord(BamlRecord bamlRecord) 
        {
            // First keep the _optimizableElementState up-to-date.  This is used to 
            // tell us if the current element is an FE or FCE (if it is,
            // we can use the optimizations).

            CheckElementStartForOptimization( bamlRecord ); 

            // Some record types should have been filtered out before the baml record 
            // collection was created by the TemplateBamlRecordReader 

            if (bamlRecord.RecordType == BamlRecordType.PIMapping || 
                bamlRecord.RecordType == BamlRecordType.AssemblyInfo ||
                bamlRecord.RecordType == BamlRecordType.TypeInfo ||
                bamlRecord.RecordType == BamlRecordType.TypeSerializerInfo ||
                bamlRecord.RecordType == BamlRecordType.AttributeInfo || 
                bamlRecord.RecordType == BamlRecordType.StringInfo ||
                bamlRecord.RecordType == BamlRecordType.DocumentStart || 
                bamlRecord.RecordType == BamlRecordType.DocumentEnd) 
            {
                // Enum.ToString(culture) is [Obsolete] 
                #pragma warning disable 0618

                ThrowException(SRID.TemplateInvalidBamlRecord,
                                bamlRecord.RecordType.ToString(XamlReaderHelper.EnglishUSCulture)); 

                #pragma warning restore 0618 
            } 

 
            // Are we in the middle of a property value that we know can't
            // be shared?  If so, add this record to the _unsharedContentCollection list.

            if (_currentState == ShareableRecordState.UnshareableSubtree) 
            {
                AddBamlRecordToUnsharedContentCollection(bamlRecord); 
 
                // Also, keep our tree-depth counters up-to-date.
 
                TrackComplexPropertyTreeDepth(bamlRecord);

                // If we reached the end of the property value that couldn't be shared, then reset
                // state (maybe the next property value will be shareable). 

                if( CurrentIsOptimizableElement() ) 
                { 
                    _currentState = ShareableRecordState.Unset;
 
                }
            }

            // Or are we in the middle of processing a set of records that is 
            // *shareable*?
 
            else if (_currentState == ShareableRecordState.BuildingShareableTree) 
            {
                // We are currently instantiating a possibly shared subtree, so pass 
                // off the baml record to the record reader for processing and
                // instantiation.  Note that the record reader will perform another
                // set of checks to determine if it needs to bail out of shareable
                // subtree processing and go back to being an unshareable subtree. 

                ReadSharedRecord( bamlRecord ); 
            } 

 
            // If we fall to this else, we're not in a shareable tree or an unshareable tree;
            // we don't know what state to be in.  We need to look at this record and figure
            // out where to put it (it may be the start of a shareable/unshareable tree).
 
            else
            { 
                ReadPotentiallyShareableRecord( bamlRecord ); 
            }
 
        }


 

        //+------------------------------------------------------------------------------------------------------ 
        // 
        //  ReadSharedRecord
        // 
        //  This is called by ReadRecord, when we're processing baml records in the template content.  It's
        //  called when we're in a tree of records that will be a shared property.  Note, though, that we
        //  may stop sharing during this routine, if the record turns out to be un-shareable.
        // 
        //+------------------------------------------------------------------------------------------------------
 
        private void ReadSharedRecord( BamlRecord bamlRecord ) 
        {
            // We are currently instantiating a possibly shared subtree, so pass 
            // off the baml record to the record reader for processing and
            // instantiation.  Note that the record reader will perform another
            // set of checks to determine if it needs to bail out of shareable
            // subtree processing and go back to being an unshareable subtree. 
            // If that is the case, change status to UnshareableSubtree and copy
            // the portion of the subtree read so far into the unshareable list. 
 
            BamlSubtreeState status = _optimizedTemplateContentHelper.ReadSubtreeRecord(bamlRecord);
 
            // Did the _optimizedTemplateContentHelper just decide that this sub-tree
            // isn't shareable after all?

            if (status == BamlSubtreeState.NotShareable) 
            {
                // Yes.  Reset our current state, copy any 
                // records that we have already passed over into the _unsharedContentCollection 
                // and continue on
 
                UnwindSharedRecords( bamlRecord );

                _currentState = ShareableRecordState.Unset; //ShareableRecordState.UnshareableSubtree;
 
            }
 
            // Or, we're still in a shareable subtree, but maybe this 
            // is the end of the subtree?
 
            else if (status == BamlSubtreeState.EndShareableSubtree)
            {
                // Yes, the subtree is shareable and we've reached the end of the tree.
                // Update the Dp value in the shared list. 

                SharedDp sdp = _sharedProperties[_sharedProperties.Count-1]; 
                sdp.Value = _optimizedTemplateContentHelper.RootList[0]; 

                // 



                Freezable freezableValue; 
                System.Windows.Data.CollectionViewSource collectionViewSource;
                bool canShare = true; 
 

                // This value is intended to be shared by all instances of the template.  So freeze it, 
                // call ME.ProvideValue on it, etc.

                StyleHelper.ProcessSharedPropertyValue(
                    _parserContext, 
                    sdp,
                    sdp.Dp, 
                    ref sdp.Value ); 

 
                // We may not actually be able to share this value, though.  In
                // that case, we'll have to release this instance.  So figure out
                // that now.
 
                if (sdp.Value == null)
                { 
                    canShare = true; 
                }
                else 
                {
                    Type valueType = sdp.Value.GetType();

                    // First, is this a shareable type? 

                    canShare = IsShareableType(valueType); 
 
                    // Second, some types are potentially shareable, but we have to inspect the instance to
                    // know for sure. 

                    if (canShare)
                    {
                        if ((freezableValue = sdp.Value as Freezable) != null) 
                        {
                            canShare = freezableValue.CanFreeze; 
                        } 
                        else if ((collectionViewSource = sdp.Value as System.Windows.Data.CollectionViewSource) != null)
                        { 
                            canShare = collectionViewSource.IsShareableInTemplate();
                        }
                    }
 
                    // Finally, the only MEs we should have at this point are
                    // binding and dynamic resources; we already called ProvideValue, 
                    // so any other ME isn't something we know about. 

                    if( canShare && valueType.IsAssignableFrom(typeof(MarkupExtension))) 
                    {
                        if( !valueType.IsAssignableFrom(typeof(BindingBase))
                            &&
                            !valueType.IsAssignableFrom(typeof(TemplateBindingExtension)) 
                            &&
                            !valueType.IsAssignableFrom(typeof(DynamicResourceExtension)) ) 
                        { 
                            canShare = false;
                        } 
                    }

                }
 
                // If it can't be shared, put the records into the unshared list.
 
                if( !canShare  ) 
                {
                    UnwindSharedRecords( bamlRecord ); 
                }
                else
                {
                    // This can be shared, so we don't need to keep this BamlRecord in memory any more. 

                    while( _bamlRecordsSubtreeStart != null ) 
                    { 
                        BamlRecord nextRecord = _bamlRecordsSubtreeStart.Next;
 
                        _bamlRecordsSubtreeStart.Unpin();

                        // Since we're not pinning this record any more, we're essentially
                        // returning it to the cache, so we want to clear any Next reference. 
                        // But if it's still pinned (i.e., it's part of a nested template),
                        // then we can't modify it. 
 
                        if( _bamlRecordsSubtreeStart.PinnedCount == 0 )
                        { 
                            _bamlRecordsSubtreeStart.Next = null;
                        }

                        if( _bamlRecordsSubtreeStart == bamlRecord ) 
                            _bamlRecordsSubtreeStart = null;
                        else 
                            _bamlRecordsSubtreeStart = nextRecord; 
                    }
 
                }

                // Reset all the status trackers.
 
                _optimizedTemplateContentHelper.Reset();
                _currentState = ShareableRecordState.Unset; 
            } 
        }
 

        //+---------------------------------------------------------------------
        //
        //  UnwindSharedRecords 
        //
        //  Remove the last property value from the _sharedProperty collection, 
        //  because, as it turns out, it's not shareable.  Put all the Baml 
        //  records for that property into the list of baml records for
        //  unshareable content (_unsharedContentCollection). 
        //
        //+----------------------------------------------------------------------

        private void UnwindSharedRecords( BamlRecord bamlRecord ) 
        {
 
            Debug.Assert( _optimizableElementState.Count >= _positionOptimizableElementState ); 

            // Update the _optimizableElementState back to where it was when we 
            // started processing this property value that we thought
            // was going to be shared.

            while( _optimizableElementState.Count > _positionOptimizableElementState ) 
            {
                _optimizableElementState.Pop(); 
            } 

            // Remove the value from the shared properties table 

            _sharedProperties.RemoveAt(_sharedProperties.Count - 1);

            // Get the baml records for this property value and put them 
            // into _unsharedContentCollection (the first baml records
            // for this value is pointed to be _bamlRecordsSubtreeStart). 
            // (This code overlaps AddContentRecord, should be a better 
            // way to share).
 
            while( _bamlRecordsSubtreeStart != null )
            {
                BamlRecord bamlRecordT = _bamlRecordsSubtreeStart;
 
                CheckElementStartForOptimization( bamlRecordT );
 
                CheckForName( bamlRecordT); 

                _unsharedContentCollection.Add(bamlRecordT); 

                if( _bamlRecordsSubtreeStart == bamlRecord )
                    _bamlRecordsSubtreeStart = null;
                else 
                    _bamlRecordsSubtreeStart = _bamlRecordsSubtreeStart.Next;
            } 
 
            _optimizedTemplateContentHelper.Reset();
        } 


        //+-------------------------------------------------------------------------------------------------
        // 
        //  ReadPotentiallyShareableRecord
        // 
        //  This is called by ReadRecord, when we're processing baml records in the template content.  It's 
        //  called when we don't know if this record should be shared or not.
        // 
        //+-------------------------------------------------------------------------------------------------


        private void ReadPotentiallyShareableRecord( BamlRecord bamlRecord ) 
        {
            DependencyProperty dp; 
            object             dpValue; 

            // Check whether this record is shareable or not. If it is 
            // shareable and is a DependencyProperty of some type, then
            // store it to be added to the template's shared value list.

            _currentState = LookForShareableRecord(bamlRecord, out dp, out dpValue); 

            // Check if we need an x:Name associated with the current element or 
            // not.  This is dependent on the current state.  Note that during this 
            // call, we could get a new/replacement bamlRecord back.
 
            CheckForName( bamlRecord);

            // If this is an unshareable record, add it to the list.
 
            if (_currentState == ShareableRecordState.UnshareableRecord ||
                _currentState == ShareableRecordState.UnshareableSubtree) 
            { 
                AddBamlRecordToUnsharedContentCollection(bamlRecord);
            } 

            // Or, maybe we're starting a (potentially) shareable subtree

            else if (_currentState == ShareableRecordState.StartShareableTree) 
            {
                // If we get to here we are starting a shared (or possibly unshared) 
                // subtree.  In this case remember where this subtree starts, in case 
                // we need to unwind.
 
                OnStartShareableTree( bamlRecord );


                // We're now in a shareable subtree mode 
                _currentState = ShareableRecordState.BuildingShareableTree;
 
                // Remember the current dp.  This may be removed if we later determine 
                // this is not a shareable subtree.
 
                _sharedProperties.Add(new SharedDp(dp, null, CurrentElementName));

            }
            else if (_currentState == ShareableRecordState.ShareableRecord) 
            {
                // The call to GetShareableRecordState above actually figured out 
                // the value for us.  First, freeze it (if it's a Freezable), since 
                // we don't handle changes to shared values.
 
                StyleHelper.ProcessSharedPropertyValue( _parserContext,
                                                        _frameworkTemplate,
                                                        dp,
                                                        ref dpValue ); 

                // Then store the property until the end of the start 
                // tag, at which point we should have the x:Name needed to add 
                // all the shared properties to the templates shared list.  Shared
                // properties that don't have the element name set yet are indicated by 
                // having a null name.

                if (String.IsNullOrEmpty(CurrentElementName))
                    _sharedProperties.Add(new SharedDp(dp, dpValue, null)); 
                else
                    _sharedProperties.Add(new SharedDp(dp, dpValue, CurrentElementName)); 
 
                // Let this record be recycled by the BamlRecordManager's cache.
 
                bamlRecord.Next = null;
                bamlRecord.Unpin();

            } 

        } 
 

        //+----------------------------------------------------------------------- 
        //
        //  OnStartShareableTree
        //
        //  This remembers some state as we start processing baml records 
        //  for a potentially shareable property value; if it turns out not to
        //  be shareable, we'll use the fields set here to unwind and put those 
        //  baml records into the unshareable collection. 
        //
        //+------------------------------------------------------------------------ 
        private void OnStartShareableTree( BamlRecord bamlRecord )
        {
            // Remember the first baml records
            _bamlRecordsSubtreeStart = bamlRecord; 

            _positionOptimizableElementState = _optimizableElementState.Count; 
        } 

 
        //+---------------------------------------------------------------------------
        //
        //  CheckElementStartForOptimization
        // 
        //  This is called by ReadRecord, and is used to keep the _optimizableElementState
        //  up-to-date.  This is used to tell us if the current element is an FE or FCE 
        //  (if it is, we can use the optimizations). 
        //
        //+---------------------------------------------------------------------------- 


        // These flags keep track of whether we're on an optimizable element,
        // i.e. one that will become a template child.  It also tracks if we're 
        // on or under a name scope.
 
        [Flags] 
        private enum OptimizableElementState
        { 
            Optimizable = 1, // An FE or FCE, and not in a nested name scope
            OnNestedNameScope =  2, // E.g. this element implements INameScope
            WhithinNestedNamescope = 4 // Has an INameScope as an ancestor
        } 

 
        private void CheckElementStartForOptimization( BamlRecord bamlRecord ) 
        {
            OptimizableElementState newState = 0; 

            // Initialize newState

            if( _optimizableElementState.Count > 0 ) 
            {
                OptimizableElementState previousState = _optimizableElementState.Peek(); 
 
                // If we were at or within a namescope before, we're within one now.
                if( (previousState 
                      & (OptimizableElementState.WhithinNestedNamescope | OptimizableElementState.OnNestedNameScope))
                      != 0
                   )
                { 
                    newState =  OptimizableElementState.WhithinNestedNamescope;
                } 
 
            }
 
            switch( bamlRecord.RecordType )
            {

                case BamlRecordType.PropertyArrayStart: 
                case BamlRecordType.PropertyIListStart:
                case BamlRecordType.PropertyIDictionaryStart: 
                /* 
                case BamlRecordType.PropertyComplexStart:
                case BamlRecordType.Text: 
                 */

                    // If we're in a property element, we're basically not
                    // in an FE or FCE any more (we won't be doing any shared 
                    // value optimizations).
 
                    _optimizableElementState.Push( newState ); 

                    break; 

                case BamlRecordType.ElementStart:

                    // If newState was set above, we don't need to update it. 
                    if( newState == 0)
                    { 
                        BamlElementStartRecord bamlElementStartRecord = bamlRecord as BamlElementStartRecord; 
                        Type elementType = MapTable.GetTypeFromId( bamlElementStartRecord.TypeId );
 
                        // If this is an IComponentConnector, then we know that is a name scope.
                        // If this is an IComponentConnector/DO, we assume it is a name scope.  This is
                        // slightly over-restrictive, but as close as we can get, while still allowing
                        // for the common UserControl scenario. 

                        if( typeof(IComponentConnector).IsAssignableFrom(elementType) 
                            && 
                            typeof(DependencyObject).IsAssignableFrom(elementType)
                            || 
                             typeof(INameScope).IsAssignableFrom(elementType) )
                        {
                            newState = OptimizableElementState.OnNestedNameScope;
                        } 

                        // If this is an FE or FCE, it is optimizable.  Note that this means 
                        // that an element can be optimizable (a template child) at a namescope, but 
                        // not below one.
 
                        if( KnownTypes.Types[(int)KnownElements.FrameworkElement].IsAssignableFrom( elementType)
                            ||
                            KnownTypes.Types[(int)KnownElements.FrameworkContentElement].IsAssignableFrom( elementType ) )
                        { 
                            newState |= OptimizableElementState.Optimizable;
                        } 
                    } 

                    _optimizableElementState.Push( newState ); 

                    break;

                case BamlRecordType.ElementEnd: 
                case BamlRecordType.PropertyArrayEnd:
                case BamlRecordType.PropertyIListEnd: 
                case BamlRecordType.PropertyIDictionaryEnd: 

                    // Pop the above stack. 

                    _optimizableElementState.Pop();

                    break; 

            } 
 
        }
 


        //+--------------------------------------------------------------------------------------
        // 
        //  TrackComplexPropertyTreeDepth
        // 
        //  Determine where we are in a subtree within a complex property.  This is 
        //  used to determine when to stop processing a shared or unshared subtree.
        // 
        //+-------------------------------------------------------------------------------------

        private void TrackComplexPropertyTreeDepth(BamlRecord bamlRecord)
        { 
        }
 
 

        //+-------------------------------------------------------------------------------------- 
        //
        //  CheckForName
        //
        //  Look for a name property within the template content records.  If we find 
        //  one, we know we can't share the record, and for FE/FCE elements we can
        //  update the shared values type for this element. 
        // 
        //+-------------------------------------------------------------------------------------
 
        private void CheckForName( BamlRecord  bamlRecord )
        {
            switch (bamlRecord.RecordType)
            { 
                case BamlRecordType.ElementStart:
 
 
                    // If we were searching for a name on the last record, we can stop
                    // searching now, we're not going to find one. 

                    if( _searchingForName )
                    {
                        _searchingForName = false; 

                        // Update the shared values table to keep the generated name. 
                        UpdateSharedPropertyNames(); 
                    }
 

                    {
                        BamlNamedElementStartRecord bamlNamedElementStartRecord = bamlRecord as BamlNamedElementStartRecord;
                        bool inFeOrFce = CurrentIsOptimizableElement(); 

 
                        // If this is an FE/FCE, name it (this temp name might get replaced later, 
                        // if the content actually has one).
 
                        if( inFeOrFce )
                        {
                            // Generate a name.  We'll use an illegal name, because we're past name validation at this
                            // point, and that guarantees that we won't have a conflict (it's invalid because it begins 
                            // with a numeric).
 
                            string newName = (_generatedNameIndex++).ToString(CultureInfo.InvariantCulture) + "_T"; 

                            // Indicate that this is a temp name, and we're still searching for a real name 
                            _searchingForName = true;

                            // Put this name on the stack and into the record.
                            _nameStack.Push( newName ); 
                            bamlNamedElementStartRecord.RuntimeName = newName;
 
                            // Also set a bit on the record indicating that this is a template child. 
                            // This is used during template application as a validation step to ensure
                            // that child elements in a template do not implement a run-time name scope. 
                            bamlNamedElementStartRecord.IsTemplateChild = true;

                        }
 
                        else
                        { 
                            // We're not in an FE/FCE, but keep the stack consistent. 
                            _nameStack.Push( String.Empty );
                        } 
                    }

                    break;
 

                case BamlRecordType.ElementEnd: 
 
                    // If we were searching for a name on the last record, we can stop
                    // searching now, we're not going to find one. 

                    if( _searchingForName )
                    {
                        _searchingForName = false; 
                        UpdateSharedPropertyNames();
                    } 
 
                    // [....] the name stack.
                    _nameStack.Pop(); 

                    break;

 
                case BamlRecordType.Property:
                case BamlRecordType.PropertyWithConverter: 
 
                    // See if we found the x:Name attribute
 
                    BamlPropertyRecord propertyRecord = bamlRecord as BamlPropertyRecord;

                    if (_searchingForName &&
                        MapTable.DoesAttributeMatch(propertyRecord.AttributeId, BamlAttributeUsage.RuntimeName)) 
                    {
                        // Yes, this is the runtime name 
 
                        // Look in the unshareable content for the generated name, and replace it with the real name.
 
                        for( int i = _unsharedContentCollection.Count - 1; i >= 0; --i )
                        {
                            if (_unsharedContentCollection[i].RecordType == BamlRecordType.ElementStart)
                            { 
                                BamlNamedElementStartRecord bamlNamedElementStartRecord = _unsharedContentCollection[i] as BamlNamedElementStartRecord;
                                if( bamlNamedElementStartRecord.RuntimeName != null ) 
                                { 
                                    bamlNamedElementStartRecord.RuntimeName = propertyRecord.Value;
                                    break; 
                                }
                            }
                        }
 
                        // Correct the name stack
 
                        _nameStack.Pop(); 
                        _nameStack.Push( propertyRecord.Value );
 
                        // Correct the naming in the shared values table

                        _searchingForName = false; // This must be set before calling UpdateSharedPropertyNames
                        UpdateSharedPropertyNames(); 

                    } 
 

                    break; 

                case BamlRecordType.PropertyTypeReference:
                case BamlRecordType.PropertyStringReference:
                case BamlRecordType.PropertyCustom: 
                case BamlRecordType.PropertyWithExtension:
 
                    break; 

                case BamlRecordType.PropertyComplexStart: 
                case BamlRecordType.PropertyArrayStart:
                case BamlRecordType.PropertyIListStart:
                case BamlRecordType.PropertyIDictionaryStart:
                case BamlRecordType.Text: 

                    // If we were searching for a name on the last record, we can stop 
                    // searching now, we're not going to find one. 

                    if( _searchingForName ) 
                    {
                        _searchingForName = false;
                        UpdateSharedPropertyNames();
                    } 

                    break; 
 

                case BamlRecordType.DefAttribute: 

                    BamlDefAttributeRecord defAttributeRecord = bamlRecord as BamlDefAttributeRecord;
                    if (defAttributeRecord.NameId == BamlMapTable.NameStringId && _searchingForName)
                    { 
                        // Look in the unshareable content for the generated name, and replace it with the real name.
 
                        for( int i = _unsharedContentCollection.Count - 1; i >= 0; --i ) 
                        {
                            if (_unsharedContentCollection[i].RecordType == BamlRecordType.ElementStart) 
                            {
                                BamlNamedElementStartRecord bamlNamedElementStartRecord = _unsharedContentCollection[i] as BamlNamedElementStartRecord;
                                if( bamlNamedElementStartRecord.RuntimeName != null )
                                { 
                                    bamlNamedElementStartRecord.RuntimeName = defAttributeRecord.Name;
                                    bamlRecord = null; 
                                    break; 
                                }
                            } 
                        }

                        // Correct the name stack
 
                        _nameStack.Pop();
                        _nameStack.Push( defAttributeRecord.Name ); 
 
                        // Correct the shared property names table
 
                        _searchingForName = false;  // This must be set before calling UpdateSharedPropertyNames
                        UpdateSharedPropertyNames();

 
                    }
                    break; 
 
                case BamlRecordType.RoutedEvent:
                case BamlRecordType.ClrEvent: 

                     // Should never reach here
                     Debug.Assert( false, "Shouldn't see events at this point in the template code" );
                     break; 

                 default: 
 
                     break;
 
            }
        }

 
        //+-----------------------------------------------------------------------------------------
        // 
        //  UpdateSharedList 
        //
        //  Update the last items on the shared DependencyProperty list with the 
        //  name of the current element.
        //
        //+-----------------------------------------------------------------------------------------
 
        private void UpdateSharedPropertyNames()
        { 
            if (_nameStack.Count > 0) 
            {
                // Get the name of the current element 
                string name = CurrentElementName;

                #if DEBUG
                int lastIndex = _frameworkTemplate._lastChildIndex; 
                int childIndex =
                #endif 
 
                // Generate an index for this name
 
                StyleHelper.CreateChildIndexFromChildName(CurrentElementName, _frameworkTemplate);

                #if DEBUG
                Debug.Assert( childIndex == lastIndex ); 
                #endif
 
                // The tail of the _sharedProperties list has the properties for this element, 
                // all with no name.  Fill in the name now.
 
                for (int i = _sharedProperties.Count - 1; i >= 0; i--)
                {
                    SharedDp sdp = _sharedProperties[i];
 
                    if (sdp.ElementName == null)
                    { 
                        sdp.ElementName = name; 
                    }
                    else 
                    {
                        break;
                    }
 
                }
            } 
 
        }
 


        //+------------------------------------------------------------------
        // 
        //  LookForShareableRecord
        // 
        //  This is called when we don't know whether or not a record can 
        //  be shared.  E.g. it's not called when we know we're in a shareable
        //  or un-shareable tree already. 
        //
        //  If the returned value is ShareableRecord, then dp and dpValue will
        //  hold the value to be shared.
        // 
        //  Properties are shareable if they're a DP, on an FE, and the property
        //  type is shareable (e.g. a Freezable that can't be frozen isn't 
        //  shareable). 
        //
        //+----------------------------------------------------------------- 

        private ShareableRecordState LookForShareableRecord(
                BamlRecord         bamlRecord,
            out DependencyProperty dp, 
            out object             dpValue)
        { 
            dp = null; 
            dpValue = null;
 
            bool isFeOrFce = CurrentIsOptimizableElement();

            // We'll assume that this isn't shareable.
 
            ShareableRecordState status = ShareableRecordState.UnshareableRecord;
 
            switch (bamlRecord.RecordType) 
            {
                // Simple properties have 5 variations: 
                //   Property that contains just a string to be converted using a typeconverter
                //            reflected for at runtime
                //   PropertyWithConverter that contains a string and the typeid for the converter
                //   PropertyTypeReference contains a typeid for a property that has a Type value 
                //   PropertyStringReference contains a string id for properties that are strings
                //   PropertyCustom contains a custom binary representation of a property 
 
                case BamlRecordType.Property:
 
                    if (isFeOrFce)
                    {
                        BamlPropertyRecord bamlPropertyRecord = bamlRecord as BamlPropertyRecord;
                        if (ParseDependencyProperty(bamlPropertyRecord.Value, 
                                                    bamlPropertyRecord.AttributeId,
                                                    0, out dp, out dpValue)) 
                        { 
                            // This is a shareable property that is a DP on an FE/FCE
                            status = ShareableRecordState.ShareableRecord; 
                        }
                    }

                    break; 

                case BamlRecordType.PropertyWithConverter: 
 
                    if( isFeOrFce )
                    { 
                        BamlPropertyWithConverterRecord bamlPropertyConverterRecord = bamlRecord as BamlPropertyWithConverterRecord;
                        if (ParseDependencyProperty(bamlPropertyConverterRecord.Value,
                                                    bamlPropertyConverterRecord.AttributeId,
                                                    bamlPropertyConverterRecord.ConverterTypeId, 
                                                    out dp, out dpValue))
                        { 
                            // This is a shareable property that is a DP on an FE/FCE 
                            status = ShareableRecordState.ShareableRecord;
                        } 
                    }
                    break;

                case BamlRecordType.PropertyTypeReference: 

                    if( isFeOrFce ) 
                    { 
                        BamlPropertyTypeReferenceRecord bamlPropertyTypeRecord = bamlRecord as BamlPropertyTypeReferenceRecord;
                        Type valueType = MapTable.GetTypeFromId(bamlPropertyTypeRecord.TypeId); 
                        dp = MapTable.GetDependencyProperty(bamlPropertyTypeRecord.AttributeId);
                        if (dp != null)
                        {
                            dpValue = valueType; 
                            // This is a shareable property that is a DP on an FE/FCE
                            status = ShareableRecordState.ShareableRecord; 
                        } 
                    }
 
                    break;

                case BamlRecordType.PropertyStringReference:
 
                    if( isFeOrFce )
                    { 
                        BamlPropertyStringReferenceRecord bamlPropertyStringRecord = bamlRecord as BamlPropertyStringReferenceRecord; 
                        string attribValue = _optimizedTemplateContentHelper.GetPropertyValueFromStringId(bamlPropertyStringRecord.StringId);
                        if (ParseDependencyProperty(attribValue, 
                                                    bamlPropertyStringRecord.AttributeId,
                                                    0, out dp, out dpValue))
                        {
                            // This is a shareable property that is a DP on an FE/FCE 
                            status = ShareableRecordState.ShareableRecord;
                        } 
                    } 

                    break; 

                case BamlRecordType.PropertyCustom:

                    BamlPropertyCustomRecord bamlPropertyCustomRecord = bamlRecord as BamlPropertyCustomRecord; 
                    if (ReadCustomProperty(bamlPropertyCustomRecord, out dp, out dpValue) && isFeOrFce)
                    { 
                        // This is a shareable property that is a DP on an FE/FCE 
                        status = ShareableRecordState.ShareableRecord;
                    } 

                    break;

                case BamlRecordType.PropertyWithExtension: 

                    if (isFeOrFce) 
                    { 
                        BamlPropertyWithExtensionRecord bamlPropertyRecord = bamlRecord as BamlPropertyWithExtensionRecord;
                        if (ReadPropertyWithExtension(bamlPropertyRecord, out dp, out dpValue)) 
                        {
                            // This is a shareable property that is a DP on an FE/FCE
                            status = ShareableRecordState.ShareableRecord;
                        } 
                    }
 
                    break; 

                // If this is a property element (complex property), we'll try to share it.  If it's 
                // some kind of collection, we don't support sharing for it; sharing for collection properties
                // gets confusing, because some people expect merge semantics rather than replacement semantics.

                case BamlRecordType.PropertyComplexStart: 

                    if (isFeOrFce) 
                    { 
                        BamlPropertyComplexStartRecord propertyComplexStartRecord = bamlRecord as BamlPropertyComplexStartRecord;
                        dp = MapTable.GetDependencyProperty(propertyComplexStartRecord.AttributeId); 

                        if (dp != null)
                        {
                            // This is a shareable property that is a DP on an FE/FCE 
                            status = ShareableRecordState.StartShareableTree;
                        } 
                    } 

                    break; 

            }

            return status; 

        } 
 
        internal bool ReadPropertyWithExtension(BamlPropertyWithExtensionRecord bamlPropertyRecord,
                                            out DependencyProperty dp, 
                                            out object propertyValue)
        {
            short attributeId = bamlPropertyRecord.AttributeId;
            dp = MapTable.GetDependencyProperty(attributeId); 
            propertyValue = null;
 
            // Not shareable if not a DP 
            if (dp == null)
            { 
                return false;
            }

            propertyValue = _optimizedTemplateContentHelper.GetExtensionValue(bamlPropertyRecord, dp.Name); 

            // MarkupExtensions are always shareable except for StaticResourceExtension. 
            bool isShareable = (bamlPropertyRecord.ExtensionTypeId != (short)KnownElements.StaticResourceExtension); 
            return isShareable;
        } 

        internal bool ReadCustomProperty(BamlPropertyCustomRecord bamlPropertyCustomRecord,
                                     out DependencyProperty dp,
                                     out object propertyValue) 
        {
            bool isShareable = false; 
            if (bamlPropertyCustomRecord.SerializerTypeId == (short)KnownElements.DependencyPropertyConverter) 
            {
                dp = null; 
                propertyValue = _optimizedTemplateContentHelper.GetCustomDependencyPropertyValue(bamlPropertyCustomRecord);
            }
            else
            { 
                string propName = null;
                Type propType = null; 
                short attributeId = bamlPropertyCustomRecord.AttributeId; 

                dp = MapTable.GetDependencyProperty(attributeId); 
                if (dp == null)
                {
                    propType = MapTable.GetCLRPropertyTypeAndNameFromId(attributeId, out propName);
                } 
                else
                { 
                    propType = dp.PropertyType; 
                    propName = dp.Name;
                } 

                // Read the custom property value into the record.
                propertyValue = _optimizedTemplateContentHelper.GetCustomValue(bamlPropertyCustomRecord, propType, propName);
 
                // Not shareable if not a DP
                if (dp != null) 
                { 
                    isShareable = IsShareable(propertyValue, propType);
                } 
            }

            return isShareable;
        } 

        private bool IsShareable(object propValue, Type propType) 
        { 
            // Not shareable if if this is a Visual or ContentElement
            if (!IsShareableType(propType)) 
            {
                return false;
            }
 
            // Not shareable if this is a Freezable that cannot be frozen.
            Freezable freezable = propValue as Freezable; 
            if (freezable != null && !freezable.CanFreeze) 
            {
                return false; 
            }

            // Otherwise assume it can be shared.
            return true; 
        }
 
        //+-------------------------------------------------------------------------------------- 
        //
        //  ParseDependencyPropeprty 
        //
        //  Process a single property value.  Return true if it is a DependencyProperty
        //  with a non-null value that is shareable.  Return false if this property
        //  is not shareable for some reason. 
        //
        //+-------------------------------------------------------------------------------------- 
 
        internal bool ParseDependencyProperty(
                string               attribValue, 
                short                attributeId,
                short                converterTypeId,
            out DependencyProperty   dp,
            out object               propertyValue) 
        {
            Debug.Assert( CurrentIsOptimizableElement() ); 
 
            // Figure out the DP from the attribute ID
 
            dp = MapTable.GetDependencyProperty(attributeId);
            propertyValue = null;

            // If we didn't find a DP, it's not shareable 

            if (dp == null) 
            { 
                return false;
            } 

            // Get the value for the DependencyProperty.

            propertyValue = XamlTypeMapper.ParseProperty(null, dp.PropertyType, dp.Name, dp, 
                                                         TypeConvertContext, _parserContext,
                                                         attribValue, converterTypeId); 
 
            return IsShareable(propertyValue, propertyValue.GetType());
        } 


        // IsShareableType
        // 
        // See if a type is at least potentially shareabl across
        // applications of a template. 
        // 
        static internal bool IsShareableType( Type t )
        { 

            if( // We handle Freezables on an per-instance basis.
                KnownTypes.Types[(int)KnownElements.Freezable].IsAssignableFrom(t)
                || 
                // Well-known immutable CLR types
                t == typeof(string) || t == typeof(Uri) ||  t == typeof(Type) 
                || 
                // We assume MEs are shareable; the host object is responsible
                // for ensuring immutability.  The exception is static resource 
                // references, for which we have special support in templates.
                (typeof(MarkupExtension).IsAssignableFrom(t)
                    &&
                    !typeof(StaticResourceExtension).IsAssignableFrom(t)) 
                ||
                // Styles & Templates are mostly shareable 
                typeof(Style).IsAssignableFrom(t) 
                ||
                typeof(FrameworkTemplate).IsAssignableFrom(t) 
                ||
                // CVS might be shareable, wait for the instance check
                typeof(CollectionViewSource).IsAssignableFrom(t)
                || 
                // Value types are immutable by nature
                t.IsValueType ) 
            { 
                return true;
            } 
            else
            {
                return false;
            } 

        } 
 
        //
        //  ReleaseSharedProperties 
        //
        //  Null out the _sharedProperties.  This is called during seal,
        //  once we've pulled everything out of the shared properties that we need.
        //  So free some heap space. 
        //
 
        internal void ReleaseSharedProperties() 
        {
            _sharedProperties = null; 
        }


#endregion Internals 

#region Helpers 
 
        //+-------------------------------------------------------------------------------------
        // 
        //  OptimizedTemplateContent helper methods
        //
        //+--------------------------------------------------------------------------------------
 
        // Throw an exception with one parameter
 
        private void ThrowException( 
            string     id,
            string     parameter1) 
        {
            string message = SR.Get(id, parameter1);
            //throw new XamlParseException(message);
            XamlParseException.ThrowException( _parserContext, _parserContext.LineNumber, _parserContext.LinePosition, message, null ); 
        }
 
 
        // The BamlMapTable from the ParserContext
 
        internal BamlMapTable MapTable
        {
            get
            { 
                // We keep this alive even after the template content
                // has been optimized, because we need it during 
                // instantiation. 

                if (_mapTable == null) 
                {
                    _mapTable = _parserContext.MapTable;
                }
 
                return _mapTable;
            } 
        } 

        // See if this optimized template is empty 

        internal bool IsEmpty
        {
            get 
            {
                return _unsharedContent == null 
                       && 
                       ( _sharedProperties == null || _sharedProperties.Count == 0 );
            } 
        }

        // The XamlTypeMapper from the ParserContext
 
        private XamlTypeMapper XamlTypeMapper
        { 
            get { return _parserContext.XamlTypeMapper; } 
        }
 

        // Wrapper to tell if the current element is an FE or an FCE
        // (using the _optimizableElementState)
 
        private bool CurrentIsOptimizableElement()
        { 
            return _optimizableElementState.Count != 0 
                   &&
                   (_optimizableElementState.Peek() & OptimizableElementState.Optimizable) != 0; 
        }


        // Generate a TypeConvertContext 

        private TypeConvertContext TypeConvertContext 
        { 
            get
            { 
                if (null == _typeConvertContext)
                {
                    _typeConvertContext = new TypeConvertContext(_parserContext);
                } 
                return _typeConvertContext;
            } 
        } 

        // Get the name of the current element 

        private string CurrentElementName
        {
            get 
            {
                // No names exist yet? 
                if (_nameStack.Count == 0) 
                    return null;
 
                // Are we still searching for a name?
                // (If so, ignore the generated name on the stack)
                else if( _searchingForName )
                    return null; 

                // Otherwise, return the real name from the stack. 
                else 
                    return _nameStack.Peek() as String;
            } 
        }

        // The Baml records that have to be re-instantiated every time.
 
        internal BamlRecord UnsharedContent
        { 
            get { return _unsharedContent; } 
        }
 
        // The property values that can be shared between instantiations
        // of the template.

        internal FrugalObjectList SharedProperties 
        {
            get { return _sharedProperties; } 
        } 

        // Type of the template content's root element (used for validation). 

        internal Type RootType
        {
            get { return _rootType; } 
        }
 
 

#endregion Helpers 

#region Data

        private ParserContext                   _parserContext; 

        private Stack  _optimizableElementState; 
 
        private BamlMapTable                    _mapTable;
        private OptimizedTemplateContentHelper  _optimizedTemplateContentHelper; 
        private FrameworkTemplate               _frameworkTemplate;
        private ShareableRecordState            _currentState;
        private bool                            _searchingForName;
 
        private BamlRecord                      _unsharedContent;
        private FrugalObjectList      _sharedProperties; 
 
        private Stack                           _nameStack;
        private Collection          _unsharedContentCollection; 
        private TypeConvertContext              _typeConvertContext;
        private BamlRecord                      _bamlRecordsSubtreeStart;

        private Type                            _rootType; // Type of the content's root element 
        private int                             _positionOptimizableElementState; // Used by StartShreableTree
 
        private int                             _generatedNameIndex = 0; 

#endregion Data 
    }

}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
/****************************************************************************\ 
*
* File:     OptimizedTemplateContent.cs
*
* Purpose:  Represents a FrameworkTemplate's content 
*           in an optimized form (separates the shareable parts of the
*           template from those which need to be re-instantiated on 
*           every use). 
*
* Copyright (C) 2005 by Microsoft Corporation.  All rights reserved. 
*
\***************************************************************************/

using System; 
using System.Xml;
using System.IO; 
using System.Windows; 
using System.Windows.Media;
using System.Windows.Navigation; 
using System.Text;
using System.Collections;
using System.Collections.Generic;
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.Collections.ObjectModel;
using System.Collections.Specialized; 

 
using System.Globalization; 
using MS.Utility;
 
namespace System.Windows.Markup
{

        /***************************************************************************\ 
        *
        * ShareableRecordState 
        * 
        * States in the sealing state machine.  Used to identify what we are currently
        * processing in ReadRecord. 
        *
        \***************************************************************************/

        internal enum ShareableRecordState 
        {
            // Initial state, or we don't know what the next state will be 
            Unset, 

            // The current record is unshareable and should be added to the unshareable list 
            UnshareableRecord,

            // We are currently within an unshareable subtree.  We will exit this subtree
            // by watching the depth of complex property tags.  All records in an 
            // unshareable subtree go into the unshared list
            UnshareableSubtree, 
 
            // The current record is a shareable dependency property, and should be added
            // to the list of shared properties 
            ShareableRecord,

            // Starting the instantiation of a possibly shared subtree under a complex
            // property.  This may end up being an unshared tree if certain conditions 
            // are encountered.
            StartShareableTree, 
 
            // In the process of building a possibly shared subtree under a complex
            // dependency property. 
            BuildingShareableTree,
        }

        /***************************************************************************\ 
        *
        * BamlSubtreeState 
        * 
        * Used by the OptimizedTemplateContentHelper to tell the OptimizedTemplateContent
        * the outcome of processing the last baml record.  This can in turn be used 
        * to modify the current ShareableRecordState.
        *
        \***************************************************************************/
 
        internal enum BamlSubtreeState
        { 
            // Record or state encountered which means the subtree can't be shared 
            NotShareable,
 
            // Successful end of a subtree that can be shared has been reached
            EndShareableSubtree,

            // Continuing to build subtree.  So far, so good. 
            ContinueShareableSubtree,
        } 
 

    internal class OptimizedTemplateContent 
    {

#region Constructor
 
        internal OptimizedTemplateContent(
            FrameworkTemplate   frameworkTemplate ) 
        { 
            _frameworkTemplate          = frameworkTemplate;
 
            _currentState               = ShareableRecordState.Unset;
            _searchingForName           = false;
            _sharedProperties           = null;
            _unsharedContentCollection  = null; 
            _unsharedContent            = null;
 
        } 

#endregion Constructor 

#region Internals

 
        //+-------------------------------------------------------------------
        // 
        //  BeginReadingContent 
        //
        //  Called by the TemplateBamlRecordReader before it starts reading 
        //  the content portion of the template.  After this, call AddContentRecord
        //  multiple times, then EndReadingContent.
        //
        //+-------------------------------------------------------------------- 

        internal void BeginReadingContent( ParserContext parserContext ) 
        { 
            // We shouldn't have been here before
 
            Debug.Assert( _unsharedContent == null );


            // Keep a copy of the parser context until EndReadingContent 

            _parserContext = parserContext; 
 
            // Initialize all the temporary buffers we need
 
            Debug.Assert( _sharedProperties == null );
            _sharedProperties         = new FrugalObjectList(16);

            Debug.Assert( _unsharedContentCollection == null ); 
            _unsharedContentCollection = new Collection();
 
            Debug.Assert( _optimizableElementState == null ); 
            _optimizableElementState = new Stack();
 
            Debug.Assert( _optimizedTemplateContentHelper == null );
            _optimizedTemplateContentHelper = new OptimizedTemplateContentHelper( parserContext );

            Debug.Assert( _nameStack == null ); 
            _nameStack = new Stack();
 
        } 

 
        //+-------------------------------------------------------------------
        //
        //  AddContentRecord
        // 
        //  Called by the TemplateBamlRecordReader when it is reading the content
        //  portion of the template.  Call BeginReadingContent before this, and 
        //  EndReadingContent afterwards. 
        //
        //+-------------------------------------------------------------------- 

        internal void AddContentRecord(BamlRecord bamlRecord )
        {
            if( _rootType == null ) 
            {
                BamlElementStartRecord bamlElementStartRecord = bamlRecord as BamlElementStartRecord; 
                _rootType = MapTable.GetTypeFromId(bamlElementStartRecord.TypeId); 
            }
 
            ReadRecord( bamlRecord );
        }

        internal void AddBamlRecordToUnsharedContentCollection(BamlRecord bamlRecord) 
        {
            _unsharedContentCollection.Add(bamlRecord); 
 
            // if this record has a Debug extension in it's Next field than install that also.
            if (BamlRecordHelper.HasDebugExtensionRecord(_parserContext.IsDebugBamlStream, bamlRecord)) 
            {
                _unsharedContentCollection.Add(bamlRecord.Next);
            }
        } 

 
        //+-------------------------------------------------------------------- 
        //
        //  EndReadingContent 
        //
        //  Called by the TemplateBamlRecordReader after it's read all the content.
        //
        //+------------------------------------------------------------------- 

        internal void EndReadingContent() 
        { 
            // Prefetch the values for static resources within the template content
 
            _frameworkTemplate.StaticResourceValues = PrefetchStaticResourceValues();

            // Link all of the unshareable content (that's how we walk through it
            // when instantiating). 

            for( int i = 0; i < _unsharedContentCollection.Count-1; i++ ) 
            { 
                _unsharedContentCollection[i].Next = _unsharedContentCollection[i+1];
            } 

            if( _unsharedContentCollection.Count > 0 )
            {
                _unsharedContentCollection[_unsharedContentCollection.Count-1].Next = null; 
            }
 
            // We're done processing the records, so we're done with 
            // the parser context and the helper objects.
 
            _typeConvertContext = null; // (From the parser context)
            _parserContext = null;

            _optimizedTemplateContentHelper = null; 
            _optimizableElementState = null;
            _nameStack = null; 
 

            #if DEBUG 
            for (int j = 0; j < _unsharedContentCollection.Count; j++)
            {
                Debug.Assert( _unsharedContentCollection[j].IsPinned );
            } 
            #endif
 
            // Since the records are linked, we can just hold on to the first 
            // record, and free the list.
 
            Debug.Assert( _unsharedContent == null );
            _unsharedContent = _unsharedContentCollection[0];
            _unsharedContentCollection = null;
 
            // Another thing we could potentially do here is process the shared values,
            // actually update the tables like StyleHelper.ProcessTemplateContent, 
            // instead of waiting for the template to be sealed.  That's more complicated 
            // code, though, and doesn't appear to be a benefit.
 
        }

        //+--------------------------------------------------------------------------
        // 
        //  PrefetchStaticResourceValues
        // 
        //  Prefetch the staticresource values wrt to the context available at 
        //  template creation time.
        // 
        //+-------------------------------------------------------------------------
        private object[] PrefetchStaticResourceValues()
        {
            object[] staticResourceValues = null; 

            if (_parserContext.InDeferredSection) 
            { 
                // Example:
                // 
                // 
                //     
                // 

                // If we are within deferred section all we need to
                // do is re-resolve the front loaded static resources 

                staticResourceValues = _parserContext.StaticResourcesStack[_parserContext.StaticResourcesStack.Count - 1]; 
 
                // Find the indices of the first and the last StaticResourceId
                // occuring within this template content. In above example this 
                // would be indices 1 - 2.

                short startId = -1;
                short endId = -1; 

                for ( int i = 0; i < _unsharedContentCollection.Count; i++ ) 
                { 
                    BamlRecord bamlRecord = _unsharedContentCollection[i];
                    BamlRecordType recordType = bamlRecord.RecordType; 

                    if (recordType == BamlRecordType.StaticResourceId ||
                        recordType == BamlRecordType.PropertyWithStaticResourceId)
                    { 
                        endId = ((BamlStaticResourceIdRecord)bamlRecord).StaticResourceId;
 
                        if (startId == -1) 
                        {
                            startId = endId; 
                        }
                    }
                }
 
                // Re-resolve the staticresources that belong to this template content and
                // fallback to the pre-fetched value if not resolved within the current context. 
 
                if (startId >= 0)
                { 
                    Debug.Assert(endId >= 0 && endId >= startId && endId < staticResourceValues.Length);

                    for ( int i = startId; i <= endId; i++ )
                    { 
                        // Note that we do not want to search the app or theme because this is
                        // only a re-resolution within the current context stack. The top-level 
                        // deferred section is the only case when we lookup the app and theme 
                        // dictionaries.
 
                        object value = _parserContext.BamlReader.FindResourceInParserStack(
                            ((DeferredResourceReference)staticResourceValues[i]).Key,
                            true /*allowDeferredResourceReference*/,
                            true /*mustReturnDeferredResourceReference*/); 

                        if (value != DependencyProperty.UnsetValue) 
                        { 
                            // If the resource was found replace the existing
                            // entry in the list of pre-fetched values 

                            staticResourceValues[i] = value;
                        }
                    } 
                }
            } 
            else 
            {
                // Example: 
                //
                // 
 
                // Find all the StaticResource records in the unshareable content
 
                // Notice that in the above scenario we only care about the static resources 
                // in the template content and the front-loaded static resources within the
                // deferable content. The StaticResourcesIds need not be altered. 

                ArrayList staticResourceValuesList = null;
                BamlRecordReader bamlReader = null;
 
                for ( int i = 0; i < _unsharedContentCollection.Count; i++ )
                { 
                    // Look for a StaticResource ElementStart record 

                    BamlRecord bamlRecord = _unsharedContentCollection[i]; 
                    BamlRecordType recordType = bamlRecord.RecordType;

                    if (recordType == BamlRecordType.ElementStart ||
                        recordType == BamlRecordType.StaticResourceStart) 
                    {
                        int positiveTypeId = -((BamlElementStartRecord)bamlRecord).TypeId; 
                        if (positiveTypeId == (int)KnownElements.StaticResourceExtension) 
                        {
                            // Find the StaticResource ElementEnd record 

                            int         elementDepth = 1;
                            BamlRecord  srStartRecord = bamlRecord;
 
                            do
                            { 
                                // Keep removing the baml records that belong to the current 
                                // static resource from the unshared list
 
                                _unsharedContentCollection.RemoveAt(i);

                                // Link records in the current static resource together
 
                                bamlRecord.Next = _unsharedContentCollection[i];
 
                                bamlRecord = _unsharedContentCollection[i]; 
                                recordType = bamlRecord.RecordType;
 
                                if (recordType == BamlRecordType.ElementStart ||
                                    recordType == BamlRecordType.StaticResourceStart)
                                {
                                    elementDepth++; 
                                }
                                else if (recordType == BamlRecordType.ElementEnd || 
                                        recordType == BamlRecordType.StaticResourceEnd) 
                                {
                                    elementDepth--; 
                                }

                            } while (elementDepth > 0);
 
                            _unsharedContentCollection.RemoveAt(i);
                            bamlRecord.Next = null; 
 
                            // Ensure that we have a BamlReader and a StaticResourceValuesList
                            EnsureBamlReaderAndStaticResourceValuesList(ref staticResourceValuesList, ref bamlReader); 

                            // Load the StaticResource records
                            bamlReader.PreParsedRecordsStart = srStartRecord;
                            bamlReader.PreParsedCurrentRecord = srStartRecord; 
                            bamlReader.Read();
                            StaticResourceExtension staticResource = (StaticResourceExtension)bamlReader.RootList[0]; 
                            bamlReader.RootList.Clear(); 

                            // Resolve the StaticResource value including lookup to the app and the theme 

                            DeferredResourceReference value = (DeferredResourceReference)bamlReader.PreviousBamlRecordReader.FindResourceInParentChain(
                                staticResource.ResourceKey,
                                true /*allowDeferredResourceReference*/, 
                                true /*mustReturnDeferredResourceReference*/);
 
                            // Add the resolved value to the static resource list 

                            staticResourceValuesList.Add(value); 

                            // Replace the static resource records in this unshared
                            // list with a StaticResourceIdRecord.
 
                            BamlStaticResourceIdRecord bamlStaticResourceIdRecord = new BamlStaticResourceIdRecord();
                            bamlStaticResourceIdRecord.StaticResourceId = (short)(staticResourceValuesList.Count - 1); 
                            bamlStaticResourceIdRecord.Pin(); 

                            _unsharedContentCollection.Insert(i, bamlStaticResourceIdRecord); 
                        }
                    }
                    else if (recordType == BamlRecordType.PropertyWithExtension ||
                             recordType == BamlRecordType.OptimizedStaticResource) 
                    {
                        IOptimizedMarkupExtension optimizedMarkupExtensionRecord = (IOptimizedMarkupExtension)bamlRecord; 
                        int positiveTypeId = optimizedMarkupExtensionRecord.ExtensionTypeId; 
                        if (positiveTypeId == (int)KnownElements.StaticResourceExtension)
                        { 
                            // Remove the baml record with the StaticResource
                            // from the unshared list

                            _unsharedContentCollection.RemoveAt(i); 
                            bamlRecord.Next = null;
 
                            // Ensure that we have a BamlReader and a StaticResourceValuesList 
                            EnsureBamlReaderAndStaticResourceValuesList(ref staticResourceValuesList, ref bamlReader);
 
                            // Load the StaticResource
                            StaticResourceExtension staticResource = (StaticResourceExtension)bamlReader.GetExtensionValue(optimizedMarkupExtensionRecord, null);

                            // Resolve the StaticResource value including lookup to the app and the theme 

                            DeferredResourceReference value = (DeferredResourceReference)bamlReader.PreviousBamlRecordReader.FindResourceInParentChain( 
                                staticResource.ResourceKey, 
                                true /*allowDeferredResourceReference*/,
                                true /*mustReturnDeferredResourceReference*/); 

                            // Add the resolved value to the static resource list

                            staticResourceValuesList.Add(value); 

                            BamlStaticResourceIdRecord bamlStaticResourceIdRecord; 
                            if (recordType == BamlRecordType.PropertyWithExtension) 
                            {
                                // Replace the PropertyWithExtensionRecord in this unshared 
                                // list with a PropertyWithStaticResourceIdRecord.

                                BamlPropertyWithStaticResourceIdRecord bamlPropertyWithStaticResourceIdRecord = new BamlPropertyWithStaticResourceIdRecord();
                                bamlPropertyWithStaticResourceIdRecord.AttributeId = ((BamlPropertyWithExtensionRecord)bamlRecord).AttributeId; 
                                bamlStaticResourceIdRecord = bamlPropertyWithStaticResourceIdRecord;
                            } 
                            else 
                            {
                                // Replace the OptimizedStaticResourceRecord in this unshared 
                                // list with a StaticResourceIdRecord.

                                bamlStaticResourceIdRecord = new BamlStaticResourceIdRecord();
                            } 

                            bamlStaticResourceIdRecord.StaticResourceId = (short)(staticResourceValuesList.Count - 1); 
                            bamlStaticResourceIdRecord.Pin(); 

                            _unsharedContentCollection.Insert(i, bamlStaticResourceIdRecord); 
                        }
                    }
                }
 
                if (staticResourceValuesList != null)
                { 
                    // Restore the reader on the ParserContext 

                    _parserContext.BamlReader = bamlReader.PreviousBamlRecordReader; 

                    staticResourceValues = staticResourceValuesList.ToArray();
                }
            } 

            return staticResourceValues; 
        } 

        //+------------------------------------------------------------------------- 
        //
        //  EnsureBamlReaderAndStaticResourceValuesList
        //
        //  Ensure that we have a BamlReader and a StaticResourceCaluesList to work with 
        //
        //+------------------------------------------------------------------------- 
        private void  EnsureBamlReaderAndStaticResourceValuesList( 
            ref ArrayList        staticResourceValuesList,
            ref BamlRecordReader bamlReader) 
        {
            if (staticResourceValuesList == null)
            {
                // This is the first StaticResource we found 
                // within the template content section
 
                staticResourceValuesList = new ArrayList(); 

                bamlReader = new BamlRecordReader(); 
                bamlReader.SetPreviousBamlRecordReader(_parserContext.BamlReader);
                bamlReader.ParserContext = _parserContext;
                bamlReader.RootList = new ArrayList(1);
            } 
        }
 
        //+-------------------------------------------------------------------------- 
        //
        //  ReadRecord 
        //
        //  Read a single record and process it.  A record is added to the
        //  _unsharedContentCollection, or the value is added to _sharedProperties.
        // 
        //+-------------------------------------------------------------------------
 
        private void ReadRecord(BamlRecord bamlRecord) 
        {
            // First keep the _optimizableElementState up-to-date.  This is used to 
            // tell us if the current element is an FE or FCE (if it is,
            // we can use the optimizations).

            CheckElementStartForOptimization( bamlRecord ); 

            // Some record types should have been filtered out before the baml record 
            // collection was created by the TemplateBamlRecordReader 

            if (bamlRecord.RecordType == BamlRecordType.PIMapping || 
                bamlRecord.RecordType == BamlRecordType.AssemblyInfo ||
                bamlRecord.RecordType == BamlRecordType.TypeInfo ||
                bamlRecord.RecordType == BamlRecordType.TypeSerializerInfo ||
                bamlRecord.RecordType == BamlRecordType.AttributeInfo || 
                bamlRecord.RecordType == BamlRecordType.StringInfo ||
                bamlRecord.RecordType == BamlRecordType.DocumentStart || 
                bamlRecord.RecordType == BamlRecordType.DocumentEnd) 
            {
                // Enum.ToString(culture) is [Obsolete] 
                #pragma warning disable 0618

                ThrowException(SRID.TemplateInvalidBamlRecord,
                                bamlRecord.RecordType.ToString(XamlReaderHelper.EnglishUSCulture)); 

                #pragma warning restore 0618 
            } 

 
            // Are we in the middle of a property value that we know can't
            // be shared?  If so, add this record to the _unsharedContentCollection list.

            if (_currentState == ShareableRecordState.UnshareableSubtree) 
            {
                AddBamlRecordToUnsharedContentCollection(bamlRecord); 
 
                // Also, keep our tree-depth counters up-to-date.
 
                TrackComplexPropertyTreeDepth(bamlRecord);

                // If we reached the end of the property value that couldn't be shared, then reset
                // state (maybe the next property value will be shareable). 

                if( CurrentIsOptimizableElement() ) 
                { 
                    _currentState = ShareableRecordState.Unset;
 
                }
            }

            // Or are we in the middle of processing a set of records that is 
            // *shareable*?
 
            else if (_currentState == ShareableRecordState.BuildingShareableTree) 
            {
                // We are currently instantiating a possibly shared subtree, so pass 
                // off the baml record to the record reader for processing and
                // instantiation.  Note that the record reader will perform another
                // set of checks to determine if it needs to bail out of shareable
                // subtree processing and go back to being an unshareable subtree. 

                ReadSharedRecord( bamlRecord ); 
            } 

 
            // If we fall to this else, we're not in a shareable tree or an unshareable tree;
            // we don't know what state to be in.  We need to look at this record and figure
            // out where to put it (it may be the start of a shareable/unshareable tree).
 
            else
            { 
                ReadPotentiallyShareableRecord( bamlRecord ); 
            }
 
        }


 

        //+------------------------------------------------------------------------------------------------------ 
        // 
        //  ReadSharedRecord
        // 
        //  This is called by ReadRecord, when we're processing baml records in the template content.  It's
        //  called when we're in a tree of records that will be a shared property.  Note, though, that we
        //  may stop sharing during this routine, if the record turns out to be un-shareable.
        // 
        //+------------------------------------------------------------------------------------------------------
 
        private void ReadSharedRecord( BamlRecord bamlRecord ) 
        {
            // We are currently instantiating a possibly shared subtree, so pass 
            // off the baml record to the record reader for processing and
            // instantiation.  Note that the record reader will perform another
            // set of checks to determine if it needs to bail out of shareable
            // subtree processing and go back to being an unshareable subtree. 
            // If that is the case, change status to UnshareableSubtree and copy
            // the portion of the subtree read so far into the unshareable list. 
 
            BamlSubtreeState status = _optimizedTemplateContentHelper.ReadSubtreeRecord(bamlRecord);
 
            // Did the _optimizedTemplateContentHelper just decide that this sub-tree
            // isn't shareable after all?

            if (status == BamlSubtreeState.NotShareable) 
            {
                // Yes.  Reset our current state, copy any 
                // records that we have already passed over into the _unsharedContentCollection 
                // and continue on
 
                UnwindSharedRecords( bamlRecord );

                _currentState = ShareableRecordState.Unset; //ShareableRecordState.UnshareableSubtree;
 
            }
 
            // Or, we're still in a shareable subtree, but maybe this 
            // is the end of the subtree?
 
            else if (status == BamlSubtreeState.EndShareableSubtree)
            {
                // Yes, the subtree is shareable and we've reached the end of the tree.
                // Update the Dp value in the shared list. 

                SharedDp sdp = _sharedProperties[_sharedProperties.Count-1]; 
                sdp.Value = _optimizedTemplateContentHelper.RootList[0]; 

                // 



                Freezable freezableValue; 
                System.Windows.Data.CollectionViewSource collectionViewSource;
                bool canShare = true; 
 

                // This value is intended to be shared by all instances of the template.  So freeze it, 
                // call ME.ProvideValue on it, etc.

                StyleHelper.ProcessSharedPropertyValue(
                    _parserContext, 
                    sdp,
                    sdp.Dp, 
                    ref sdp.Value ); 

 
                // We may not actually be able to share this value, though.  In
                // that case, we'll have to release this instance.  So figure out
                // that now.
 
                if (sdp.Value == null)
                { 
                    canShare = true; 
                }
                else 
                {
                    Type valueType = sdp.Value.GetType();

                    // First, is this a shareable type? 

                    canShare = IsShareableType(valueType); 
 
                    // Second, some types are potentially shareable, but we have to inspect the instance to
                    // know for sure. 

                    if (canShare)
                    {
                        if ((freezableValue = sdp.Value as Freezable) != null) 
                        {
                            canShare = freezableValue.CanFreeze; 
                        } 
                        else if ((collectionViewSource = sdp.Value as System.Windows.Data.CollectionViewSource) != null)
                        { 
                            canShare = collectionViewSource.IsShareableInTemplate();
                        }
                    }
 
                    // Finally, the only MEs we should have at this point are
                    // binding and dynamic resources; we already called ProvideValue, 
                    // so any other ME isn't something we know about. 

                    if( canShare && valueType.IsAssignableFrom(typeof(MarkupExtension))) 
                    {
                        if( !valueType.IsAssignableFrom(typeof(BindingBase))
                            &&
                            !valueType.IsAssignableFrom(typeof(TemplateBindingExtension)) 
                            &&
                            !valueType.IsAssignableFrom(typeof(DynamicResourceExtension)) ) 
                        { 
                            canShare = false;
                        } 
                    }

                }
 
                // If it can't be shared, put the records into the unshared list.
 
                if( !canShare  ) 
                {
                    UnwindSharedRecords( bamlRecord ); 
                }
                else
                {
                    // This can be shared, so we don't need to keep this BamlRecord in memory any more. 

                    while( _bamlRecordsSubtreeStart != null ) 
                    { 
                        BamlRecord nextRecord = _bamlRecordsSubtreeStart.Next;
 
                        _bamlRecordsSubtreeStart.Unpin();

                        // Since we're not pinning this record any more, we're essentially
                        // returning it to the cache, so we want to clear any Next reference. 
                        // But if it's still pinned (i.e., it's part of a nested template),
                        // then we can't modify it. 
 
                        if( _bamlRecordsSubtreeStart.PinnedCount == 0 )
                        { 
                            _bamlRecordsSubtreeStart.Next = null;
                        }

                        if( _bamlRecordsSubtreeStart == bamlRecord ) 
                            _bamlRecordsSubtreeStart = null;
                        else 
                            _bamlRecordsSubtreeStart = nextRecord; 
                    }
 
                }

                // Reset all the status trackers.
 
                _optimizedTemplateContentHelper.Reset();
                _currentState = ShareableRecordState.Unset; 
            } 
        }
 

        //+---------------------------------------------------------------------
        //
        //  UnwindSharedRecords 
        //
        //  Remove the last property value from the _sharedProperty collection, 
        //  because, as it turns out, it's not shareable.  Put all the Baml 
        //  records for that property into the list of baml records for
        //  unshareable content (_unsharedContentCollection). 
        //
        //+----------------------------------------------------------------------

        private void UnwindSharedRecords( BamlRecord bamlRecord ) 
        {
 
            Debug.Assert( _optimizableElementState.Count >= _positionOptimizableElementState ); 

            // Update the _optimizableElementState back to where it was when we 
            // started processing this property value that we thought
            // was going to be shared.

            while( _optimizableElementState.Count > _positionOptimizableElementState ) 
            {
                _optimizableElementState.Pop(); 
            } 

            // Remove the value from the shared properties table 

            _sharedProperties.RemoveAt(_sharedProperties.Count - 1);

            // Get the baml records for this property value and put them 
            // into _unsharedContentCollection (the first baml records
            // for this value is pointed to be _bamlRecordsSubtreeStart). 
            // (This code overlaps AddContentRecord, should be a better 
            // way to share).
 
            while( _bamlRecordsSubtreeStart != null )
            {
                BamlRecord bamlRecordT = _bamlRecordsSubtreeStart;
 
                CheckElementStartForOptimization( bamlRecordT );
 
                CheckForName( bamlRecordT); 

                _unsharedContentCollection.Add(bamlRecordT); 

                if( _bamlRecordsSubtreeStart == bamlRecord )
                    _bamlRecordsSubtreeStart = null;
                else 
                    _bamlRecordsSubtreeStart = _bamlRecordsSubtreeStart.Next;
            } 
 
            _optimizedTemplateContentHelper.Reset();
        } 


        //+-------------------------------------------------------------------------------------------------
        // 
        //  ReadPotentiallyShareableRecord
        // 
        //  This is called by ReadRecord, when we're processing baml records in the template content.  It's 
        //  called when we don't know if this record should be shared or not.
        // 
        //+-------------------------------------------------------------------------------------------------


        private void ReadPotentiallyShareableRecord( BamlRecord bamlRecord ) 
        {
            DependencyProperty dp; 
            object             dpValue; 

            // Check whether this record is shareable or not. If it is 
            // shareable and is a DependencyProperty of some type, then
            // store it to be added to the template's shared value list.

            _currentState = LookForShareableRecord(bamlRecord, out dp, out dpValue); 

            // Check if we need an x:Name associated with the current element or 
            // not.  This is dependent on the current state.  Note that during this 
            // call, we could get a new/replacement bamlRecord back.
 
            CheckForName( bamlRecord);

            // If this is an unshareable record, add it to the list.
 
            if (_currentState == ShareableRecordState.UnshareableRecord ||
                _currentState == ShareableRecordState.UnshareableSubtree) 
            { 
                AddBamlRecordToUnsharedContentCollection(bamlRecord);
            } 

            // Or, maybe we're starting a (potentially) shareable subtree

            else if (_currentState == ShareableRecordState.StartShareableTree) 
            {
                // If we get to here we are starting a shared (or possibly unshared) 
                // subtree.  In this case remember where this subtree starts, in case 
                // we need to unwind.
 
                OnStartShareableTree( bamlRecord );


                // We're now in a shareable subtree mode 
                _currentState = ShareableRecordState.BuildingShareableTree;
 
                // Remember the current dp.  This may be removed if we later determine 
                // this is not a shareable subtree.
 
                _sharedProperties.Add(new SharedDp(dp, null, CurrentElementName));

            }
            else if (_currentState == ShareableRecordState.ShareableRecord) 
            {
                // The call to GetShareableRecordState above actually figured out 
                // the value for us.  First, freeze it (if it's a Freezable), since 
                // we don't handle changes to shared values.
 
                StyleHelper.ProcessSharedPropertyValue( _parserContext,
                                                        _frameworkTemplate,
                                                        dp,
                                                        ref dpValue ); 

                // Then store the property until the end of the start 
                // tag, at which point we should have the x:Name needed to add 
                // all the shared properties to the templates shared list.  Shared
                // properties that don't have the element name set yet are indicated by 
                // having a null name.

                if (String.IsNullOrEmpty(CurrentElementName))
                    _sharedProperties.Add(new SharedDp(dp, dpValue, null)); 
                else
                    _sharedProperties.Add(new SharedDp(dp, dpValue, CurrentElementName)); 
 
                // Let this record be recycled by the BamlRecordManager's cache.
 
                bamlRecord.Next = null;
                bamlRecord.Unpin();

            } 

        } 
 

        //+----------------------------------------------------------------------- 
        //
        //  OnStartShareableTree
        //
        //  This remembers some state as we start processing baml records 
        //  for a potentially shareable property value; if it turns out not to
        //  be shareable, we'll use the fields set here to unwind and put those 
        //  baml records into the unshareable collection. 
        //
        //+------------------------------------------------------------------------ 
        private void OnStartShareableTree( BamlRecord bamlRecord )
        {
            // Remember the first baml records
            _bamlRecordsSubtreeStart = bamlRecord; 

            _positionOptimizableElementState = _optimizableElementState.Count; 
        } 

 
        //+---------------------------------------------------------------------------
        //
        //  CheckElementStartForOptimization
        // 
        //  This is called by ReadRecord, and is used to keep the _optimizableElementState
        //  up-to-date.  This is used to tell us if the current element is an FE or FCE 
        //  (if it is, we can use the optimizations). 
        //
        //+---------------------------------------------------------------------------- 


        // These flags keep track of whether we're on an optimizable element,
        // i.e. one that will become a template child.  It also tracks if we're 
        // on or under a name scope.
 
        [Flags] 
        private enum OptimizableElementState
        { 
            Optimizable = 1, // An FE or FCE, and not in a nested name scope
            OnNestedNameScope =  2, // E.g. this element implements INameScope
            WhithinNestedNamescope = 4 // Has an INameScope as an ancestor
        } 

 
        private void CheckElementStartForOptimization( BamlRecord bamlRecord ) 
        {
            OptimizableElementState newState = 0; 

            // Initialize newState

            if( _optimizableElementState.Count > 0 ) 
            {
                OptimizableElementState previousState = _optimizableElementState.Peek(); 
 
                // If we were at or within a namescope before, we're within one now.
                if( (previousState 
                      & (OptimizableElementState.WhithinNestedNamescope | OptimizableElementState.OnNestedNameScope))
                      != 0
                   )
                { 
                    newState =  OptimizableElementState.WhithinNestedNamescope;
                } 
 
            }
 
            switch( bamlRecord.RecordType )
            {

                case BamlRecordType.PropertyArrayStart: 
                case BamlRecordType.PropertyIListStart:
                case BamlRecordType.PropertyIDictionaryStart: 
                /* 
                case BamlRecordType.PropertyComplexStart:
                case BamlRecordType.Text: 
                 */

                    // If we're in a property element, we're basically not
                    // in an FE or FCE any more (we won't be doing any shared 
                    // value optimizations).
 
                    _optimizableElementState.Push( newState ); 

                    break; 

                case BamlRecordType.ElementStart:

                    // If newState was set above, we don't need to update it. 
                    if( newState == 0)
                    { 
                        BamlElementStartRecord bamlElementStartRecord = bamlRecord as BamlElementStartRecord; 
                        Type elementType = MapTable.GetTypeFromId( bamlElementStartRecord.TypeId );
 
                        // If this is an IComponentConnector, then we know that is a name scope.
                        // If this is an IComponentConnector/DO, we assume it is a name scope.  This is
                        // slightly over-restrictive, but as close as we can get, while still allowing
                        // for the common UserControl scenario. 

                        if( typeof(IComponentConnector).IsAssignableFrom(elementType) 
                            && 
                            typeof(DependencyObject).IsAssignableFrom(elementType)
                            || 
                             typeof(INameScope).IsAssignableFrom(elementType) )
                        {
                            newState = OptimizableElementState.OnNestedNameScope;
                        } 

                        // If this is an FE or FCE, it is optimizable.  Note that this means 
                        // that an element can be optimizable (a template child) at a namescope, but 
                        // not below one.
 
                        if( KnownTypes.Types[(int)KnownElements.FrameworkElement].IsAssignableFrom( elementType)
                            ||
                            KnownTypes.Types[(int)KnownElements.FrameworkContentElement].IsAssignableFrom( elementType ) )
                        { 
                            newState |= OptimizableElementState.Optimizable;
                        } 
                    } 

                    _optimizableElementState.Push( newState ); 

                    break;

                case BamlRecordType.ElementEnd: 
                case BamlRecordType.PropertyArrayEnd:
                case BamlRecordType.PropertyIListEnd: 
                case BamlRecordType.PropertyIDictionaryEnd: 

                    // Pop the above stack. 

                    _optimizableElementState.Pop();

                    break; 

            } 
 
        }
 


        //+--------------------------------------------------------------------------------------
        // 
        //  TrackComplexPropertyTreeDepth
        // 
        //  Determine where we are in a subtree within a complex property.  This is 
        //  used to determine when to stop processing a shared or unshared subtree.
        // 
        //+-------------------------------------------------------------------------------------

        private void TrackComplexPropertyTreeDepth(BamlRecord bamlRecord)
        { 
        }
 
 

        //+-------------------------------------------------------------------------------------- 
        //
        //  CheckForName
        //
        //  Look for a name property within the template content records.  If we find 
        //  one, we know we can't share the record, and for FE/FCE elements we can
        //  update the shared values type for this element. 
        // 
        //+-------------------------------------------------------------------------------------
 
        private void CheckForName( BamlRecord  bamlRecord )
        {
            switch (bamlRecord.RecordType)
            { 
                case BamlRecordType.ElementStart:
 
 
                    // If we were searching for a name on the last record, we can stop
                    // searching now, we're not going to find one. 

                    if( _searchingForName )
                    {
                        _searchingForName = false; 

                        // Update the shared values table to keep the generated name. 
                        UpdateSharedPropertyNames(); 
                    }
 

                    {
                        BamlNamedElementStartRecord bamlNamedElementStartRecord = bamlRecord as BamlNamedElementStartRecord;
                        bool inFeOrFce = CurrentIsOptimizableElement(); 

 
                        // If this is an FE/FCE, name it (this temp name might get replaced later, 
                        // if the content actually has one).
 
                        if( inFeOrFce )
                        {
                            // Generate a name.  We'll use an illegal name, because we're past name validation at this
                            // point, and that guarantees that we won't have a conflict (it's invalid because it begins 
                            // with a numeric).
 
                            string newName = (_generatedNameIndex++).ToString(CultureInfo.InvariantCulture) + "_T"; 

                            // Indicate that this is a temp name, and we're still searching for a real name 
                            _searchingForName = true;

                            // Put this name on the stack and into the record.
                            _nameStack.Push( newName ); 
                            bamlNamedElementStartRecord.RuntimeName = newName;
 
                            // Also set a bit on the record indicating that this is a template child. 
                            // This is used during template application as a validation step to ensure
                            // that child elements in a template do not implement a run-time name scope. 
                            bamlNamedElementStartRecord.IsTemplateChild = true;

                        }
 
                        else
                        { 
                            // We're not in an FE/FCE, but keep the stack consistent. 
                            _nameStack.Push( String.Empty );
                        } 
                    }

                    break;
 

                case BamlRecordType.ElementEnd: 
 
                    // If we were searching for a name on the last record, we can stop
                    // searching now, we're not going to find one. 

                    if( _searchingForName )
                    {
                        _searchingForName = false; 
                        UpdateSharedPropertyNames();
                    } 
 
                    // [....] the name stack.
                    _nameStack.Pop(); 

                    break;

 
                case BamlRecordType.Property:
                case BamlRecordType.PropertyWithConverter: 
 
                    // See if we found the x:Name attribute
 
                    BamlPropertyRecord propertyRecord = bamlRecord as BamlPropertyRecord;

                    if (_searchingForName &&
                        MapTable.DoesAttributeMatch(propertyRecord.AttributeId, BamlAttributeUsage.RuntimeName)) 
                    {
                        // Yes, this is the runtime name 
 
                        // Look in the unshareable content for the generated name, and replace it with the real name.
 
                        for( int i = _unsharedContentCollection.Count - 1; i >= 0; --i )
                        {
                            if (_unsharedContentCollection[i].RecordType == BamlRecordType.ElementStart)
                            { 
                                BamlNamedElementStartRecord bamlNamedElementStartRecord = _unsharedContentCollection[i] as BamlNamedElementStartRecord;
                                if( bamlNamedElementStartRecord.RuntimeName != null ) 
                                { 
                                    bamlNamedElementStartRecord.RuntimeName = propertyRecord.Value;
                                    break; 
                                }
                            }
                        }
 
                        // Correct the name stack
 
                        _nameStack.Pop(); 
                        _nameStack.Push( propertyRecord.Value );
 
                        // Correct the naming in the shared values table

                        _searchingForName = false; // This must be set before calling UpdateSharedPropertyNames
                        UpdateSharedPropertyNames(); 

                    } 
 

                    break; 

                case BamlRecordType.PropertyTypeReference:
                case BamlRecordType.PropertyStringReference:
                case BamlRecordType.PropertyCustom: 
                case BamlRecordType.PropertyWithExtension:
 
                    break; 

                case BamlRecordType.PropertyComplexStart: 
                case BamlRecordType.PropertyArrayStart:
                case BamlRecordType.PropertyIListStart:
                case BamlRecordType.PropertyIDictionaryStart:
                case BamlRecordType.Text: 

                    // If we were searching for a name on the last record, we can stop 
                    // searching now, we're not going to find one. 

                    if( _searchingForName ) 
                    {
                        _searchingForName = false;
                        UpdateSharedPropertyNames();
                    } 

                    break; 
 

                case BamlRecordType.DefAttribute: 

                    BamlDefAttributeRecord defAttributeRecord = bamlRecord as BamlDefAttributeRecord;
                    if (defAttributeRecord.NameId == BamlMapTable.NameStringId && _searchingForName)
                    { 
                        // Look in the unshareable content for the generated name, and replace it with the real name.
 
                        for( int i = _unsharedContentCollection.Count - 1; i >= 0; --i ) 
                        {
                            if (_unsharedContentCollection[i].RecordType == BamlRecordType.ElementStart) 
                            {
                                BamlNamedElementStartRecord bamlNamedElementStartRecord = _unsharedContentCollection[i] as BamlNamedElementStartRecord;
                                if( bamlNamedElementStartRecord.RuntimeName != null )
                                { 
                                    bamlNamedElementStartRecord.RuntimeName = defAttributeRecord.Name;
                                    bamlRecord = null; 
                                    break; 
                                }
                            } 
                        }

                        // Correct the name stack
 
                        _nameStack.Pop();
                        _nameStack.Push( defAttributeRecord.Name ); 
 
                        // Correct the shared property names table
 
                        _searchingForName = false;  // This must be set before calling UpdateSharedPropertyNames
                        UpdateSharedPropertyNames();

 
                    }
                    break; 
 
                case BamlRecordType.RoutedEvent:
                case BamlRecordType.ClrEvent: 

                     // Should never reach here
                     Debug.Assert( false, "Shouldn't see events at this point in the template code" );
                     break; 

                 default: 
 
                     break;
 
            }
        }

 
        //+-----------------------------------------------------------------------------------------
        // 
        //  UpdateSharedList 
        //
        //  Update the last items on the shared DependencyProperty list with the 
        //  name of the current element.
        //
        //+-----------------------------------------------------------------------------------------
 
        private void UpdateSharedPropertyNames()
        { 
            if (_nameStack.Count > 0) 
            {
                // Get the name of the current element 
                string name = CurrentElementName;

                #if DEBUG
                int lastIndex = _frameworkTemplate._lastChildIndex; 
                int childIndex =
                #endif 
 
                // Generate an index for this name
 
                StyleHelper.CreateChildIndexFromChildName(CurrentElementName, _frameworkTemplate);

                #if DEBUG
                Debug.Assert( childIndex == lastIndex ); 
                #endif
 
                // The tail of the _sharedProperties list has the properties for this element, 
                // all with no name.  Fill in the name now.
 
                for (int i = _sharedProperties.Count - 1; i >= 0; i--)
                {
                    SharedDp sdp = _sharedProperties[i];
 
                    if (sdp.ElementName == null)
                    { 
                        sdp.ElementName = name; 
                    }
                    else 
                    {
                        break;
                    }
 
                }
            } 
 
        }
 


        //+------------------------------------------------------------------
        // 
        //  LookForShareableRecord
        // 
        //  This is called when we don't know whether or not a record can 
        //  be shared.  E.g. it's not called when we know we're in a shareable
        //  or un-shareable tree already. 
        //
        //  If the returned value is ShareableRecord, then dp and dpValue will
        //  hold the value to be shared.
        // 
        //  Properties are shareable if they're a DP, on an FE, and the property
        //  type is shareable (e.g. a Freezable that can't be frozen isn't 
        //  shareable). 
        //
        //+----------------------------------------------------------------- 

        private ShareableRecordState LookForShareableRecord(
                BamlRecord         bamlRecord,
            out DependencyProperty dp, 
            out object             dpValue)
        { 
            dp = null; 
            dpValue = null;
 
            bool isFeOrFce = CurrentIsOptimizableElement();

            // We'll assume that this isn't shareable.
 
            ShareableRecordState status = ShareableRecordState.UnshareableRecord;
 
            switch (bamlRecord.RecordType) 
            {
                // Simple properties have 5 variations: 
                //   Property that contains just a string to be converted using a typeconverter
                //            reflected for at runtime
                //   PropertyWithConverter that contains a string and the typeid for the converter
                //   PropertyTypeReference contains a typeid for a property that has a Type value 
                //   PropertyStringReference contains a string id for properties that are strings
                //   PropertyCustom contains a custom binary representation of a property 
 
                case BamlRecordType.Property:
 
                    if (isFeOrFce)
                    {
                        BamlPropertyRecord bamlPropertyRecord = bamlRecord as BamlPropertyRecord;
                        if (ParseDependencyProperty(bamlPropertyRecord.Value, 
                                                    bamlPropertyRecord.AttributeId,
                                                    0, out dp, out dpValue)) 
                        { 
                            // This is a shareable property that is a DP on an FE/FCE
                            status = ShareableRecordState.ShareableRecord; 
                        }
                    }

                    break; 

                case BamlRecordType.PropertyWithConverter: 
 
                    if( isFeOrFce )
                    { 
                        BamlPropertyWithConverterRecord bamlPropertyConverterRecord = bamlRecord as BamlPropertyWithConverterRecord;
                        if (ParseDependencyProperty(bamlPropertyConverterRecord.Value,
                                                    bamlPropertyConverterRecord.AttributeId,
                                                    bamlPropertyConverterRecord.ConverterTypeId, 
                                                    out dp, out dpValue))
                        { 
                            // This is a shareable property that is a DP on an FE/FCE 
                            status = ShareableRecordState.ShareableRecord;
                        } 
                    }
                    break;

                case BamlRecordType.PropertyTypeReference: 

                    if( isFeOrFce ) 
                    { 
                        BamlPropertyTypeReferenceRecord bamlPropertyTypeRecord = bamlRecord as BamlPropertyTypeReferenceRecord;
                        Type valueType = MapTable.GetTypeFromId(bamlPropertyTypeRecord.TypeId); 
                        dp = MapTable.GetDependencyProperty(bamlPropertyTypeRecord.AttributeId);
                        if (dp != null)
                        {
                            dpValue = valueType; 
                            // This is a shareable property that is a DP on an FE/FCE
                            status = ShareableRecordState.ShareableRecord; 
                        } 
                    }
 
                    break;

                case BamlRecordType.PropertyStringReference:
 
                    if( isFeOrFce )
                    { 
                        BamlPropertyStringReferenceRecord bamlPropertyStringRecord = bamlRecord as BamlPropertyStringReferenceRecord; 
                        string attribValue = _optimizedTemplateContentHelper.GetPropertyValueFromStringId(bamlPropertyStringRecord.StringId);
                        if (ParseDependencyProperty(attribValue, 
                                                    bamlPropertyStringRecord.AttributeId,
                                                    0, out dp, out dpValue))
                        {
                            // This is a shareable property that is a DP on an FE/FCE 
                            status = ShareableRecordState.ShareableRecord;
                        } 
                    } 

                    break; 

                case BamlRecordType.PropertyCustom:

                    BamlPropertyCustomRecord bamlPropertyCustomRecord = bamlRecord as BamlPropertyCustomRecord; 
                    if (ReadCustomProperty(bamlPropertyCustomRecord, out dp, out dpValue) && isFeOrFce)
                    { 
                        // This is a shareable property that is a DP on an FE/FCE 
                        status = ShareableRecordState.ShareableRecord;
                    } 

                    break;

                case BamlRecordType.PropertyWithExtension: 

                    if (isFeOrFce) 
                    { 
                        BamlPropertyWithExtensionRecord bamlPropertyRecord = bamlRecord as BamlPropertyWithExtensionRecord;
                        if (ReadPropertyWithExtension(bamlPropertyRecord, out dp, out dpValue)) 
                        {
                            // This is a shareable property that is a DP on an FE/FCE
                            status = ShareableRecordState.ShareableRecord;
                        } 
                    }
 
                    break; 

                // If this is a property element (complex property), we'll try to share it.  If it's 
                // some kind of collection, we don't support sharing for it; sharing for collection properties
                // gets confusing, because some people expect merge semantics rather than replacement semantics.

                case BamlRecordType.PropertyComplexStart: 

                    if (isFeOrFce) 
                    { 
                        BamlPropertyComplexStartRecord propertyComplexStartRecord = bamlRecord as BamlPropertyComplexStartRecord;
                        dp = MapTable.GetDependencyProperty(propertyComplexStartRecord.AttributeId); 

                        if (dp != null)
                        {
                            // This is a shareable property that is a DP on an FE/FCE 
                            status = ShareableRecordState.StartShareableTree;
                        } 
                    } 

                    break; 

            }

            return status; 

        } 
 
        internal bool ReadPropertyWithExtension(BamlPropertyWithExtensionRecord bamlPropertyRecord,
                                            out DependencyProperty dp, 
                                            out object propertyValue)
        {
            short attributeId = bamlPropertyRecord.AttributeId;
            dp = MapTable.GetDependencyProperty(attributeId); 
            propertyValue = null;
 
            // Not shareable if not a DP 
            if (dp == null)
            { 
                return false;
            }

            propertyValue = _optimizedTemplateContentHelper.GetExtensionValue(bamlPropertyRecord, dp.Name); 

            // MarkupExtensions are always shareable except for StaticResourceExtension. 
            bool isShareable = (bamlPropertyRecord.ExtensionTypeId != (short)KnownElements.StaticResourceExtension); 
            return isShareable;
        } 

        internal bool ReadCustomProperty(BamlPropertyCustomRecord bamlPropertyCustomRecord,
                                     out DependencyProperty dp,
                                     out object propertyValue) 
        {
            bool isShareable = false; 
            if (bamlPropertyCustomRecord.SerializerTypeId == (short)KnownElements.DependencyPropertyConverter) 
            {
                dp = null; 
                propertyValue = _optimizedTemplateContentHelper.GetCustomDependencyPropertyValue(bamlPropertyCustomRecord);
            }
            else
            { 
                string propName = null;
                Type propType = null; 
                short attributeId = bamlPropertyCustomRecord.AttributeId; 

                dp = MapTable.GetDependencyProperty(attributeId); 
                if (dp == null)
                {
                    propType = MapTable.GetCLRPropertyTypeAndNameFromId(attributeId, out propName);
                } 
                else
                { 
                    propType = dp.PropertyType; 
                    propName = dp.Name;
                } 

                // Read the custom property value into the record.
                propertyValue = _optimizedTemplateContentHelper.GetCustomValue(bamlPropertyCustomRecord, propType, propName);
 
                // Not shareable if not a DP
                if (dp != null) 
                { 
                    isShareable = IsShareable(propertyValue, propType);
                } 
            }

            return isShareable;
        } 

        private bool IsShareable(object propValue, Type propType) 
        { 
            // Not shareable if if this is a Visual or ContentElement
            if (!IsShareableType(propType)) 
            {
                return false;
            }
 
            // Not shareable if this is a Freezable that cannot be frozen.
            Freezable freezable = propValue as Freezable; 
            if (freezable != null && !freezable.CanFreeze) 
            {
                return false; 
            }

            // Otherwise assume it can be shared.
            return true; 
        }
 
        //+-------------------------------------------------------------------------------------- 
        //
        //  ParseDependencyPropeprty 
        //
        //  Process a single property value.  Return true if it is a DependencyProperty
        //  with a non-null value that is shareable.  Return false if this property
        //  is not shareable for some reason. 
        //
        //+-------------------------------------------------------------------------------------- 
 
        internal bool ParseDependencyProperty(
                string               attribValue, 
                short                attributeId,
                short                converterTypeId,
            out DependencyProperty   dp,
            out object               propertyValue) 
        {
            Debug.Assert( CurrentIsOptimizableElement() ); 
 
            // Figure out the DP from the attribute ID
 
            dp = MapTable.GetDependencyProperty(attributeId);
            propertyValue = null;

            // If we didn't find a DP, it's not shareable 

            if (dp == null) 
            { 
                return false;
            } 

            // Get the value for the DependencyProperty.

            propertyValue = XamlTypeMapper.ParseProperty(null, dp.PropertyType, dp.Name, dp, 
                                                         TypeConvertContext, _parserContext,
                                                         attribValue, converterTypeId); 
 
            return IsShareable(propertyValue, propertyValue.GetType());
        } 


        // IsShareableType
        // 
        // See if a type is at least potentially shareabl across
        // applications of a template. 
        // 
        static internal bool IsShareableType( Type t )
        { 

            if( // We handle Freezables on an per-instance basis.
                KnownTypes.Types[(int)KnownElements.Freezable].IsAssignableFrom(t)
                || 
                // Well-known immutable CLR types
                t == typeof(string) || t == typeof(Uri) ||  t == typeof(Type) 
                || 
                // We assume MEs are shareable; the host object is responsible
                // for ensuring immutability.  The exception is static resource 
                // references, for which we have special support in templates.
                (typeof(MarkupExtension).IsAssignableFrom(t)
                    &&
                    !typeof(StaticResourceExtension).IsAssignableFrom(t)) 
                ||
                // Styles & Templates are mostly shareable 
                typeof(Style).IsAssignableFrom(t) 
                ||
                typeof(FrameworkTemplate).IsAssignableFrom(t) 
                ||
                // CVS might be shareable, wait for the instance check
                typeof(CollectionViewSource).IsAssignableFrom(t)
                || 
                // Value types are immutable by nature
                t.IsValueType ) 
            { 
                return true;
            } 
            else
            {
                return false;
            } 

        } 
 
        //
        //  ReleaseSharedProperties 
        //
        //  Null out the _sharedProperties.  This is called during seal,
        //  once we've pulled everything out of the shared properties that we need.
        //  So free some heap space. 
        //
 
        internal void ReleaseSharedProperties() 
        {
            _sharedProperties = null; 
        }


#endregion Internals 

#region Helpers 
 
        //+-------------------------------------------------------------------------------------
        // 
        //  OptimizedTemplateContent helper methods
        //
        //+--------------------------------------------------------------------------------------
 
        // Throw an exception with one parameter
 
        private void ThrowException( 
            string     id,
            string     parameter1) 
        {
            string message = SR.Get(id, parameter1);
            //throw new XamlParseException(message);
            XamlParseException.ThrowException( _parserContext, _parserContext.LineNumber, _parserContext.LinePosition, message, null ); 
        }
 
 
        // The BamlMapTable from the ParserContext
 
        internal BamlMapTable MapTable
        {
            get
            { 
                // We keep this alive even after the template content
                // has been optimized, because we need it during 
                // instantiation. 

                if (_mapTable == null) 
                {
                    _mapTable = _parserContext.MapTable;
                }
 
                return _mapTable;
            } 
        } 

        // See if this optimized template is empty 

        internal bool IsEmpty
        {
            get 
            {
                return _unsharedContent == null 
                       && 
                       ( _sharedProperties == null || _sharedProperties.Count == 0 );
            } 
        }

        // The XamlTypeMapper from the ParserContext
 
        private XamlTypeMapper XamlTypeMapper
        { 
            get { return _parserContext.XamlTypeMapper; } 
        }
 

        // Wrapper to tell if the current element is an FE or an FCE
        // (using the _optimizableElementState)
 
        private bool CurrentIsOptimizableElement()
        { 
            return _optimizableElementState.Count != 0 
                   &&
                   (_optimizableElementState.Peek() & OptimizableElementState.Optimizable) != 0; 
        }


        // Generate a TypeConvertContext 

        private TypeConvertContext TypeConvertContext 
        { 
            get
            { 
                if (null == _typeConvertContext)
                {
                    _typeConvertContext = new TypeConvertContext(_parserContext);
                } 
                return _typeConvertContext;
            } 
        } 

        // Get the name of the current element 

        private string CurrentElementName
        {
            get 
            {
                // No names exist yet? 
                if (_nameStack.Count == 0) 
                    return null;
 
                // Are we still searching for a name?
                // (If so, ignore the generated name on the stack)
                else if( _searchingForName )
                    return null; 

                // Otherwise, return the real name from the stack. 
                else 
                    return _nameStack.Peek() as String;
            } 
        }

        // The Baml records that have to be re-instantiated every time.
 
        internal BamlRecord UnsharedContent
        { 
            get { return _unsharedContent; } 
        }
 
        // The property values that can be shared between instantiations
        // of the template.

        internal FrugalObjectList SharedProperties 
        {
            get { return _sharedProperties; } 
        } 

        // Type of the template content's root element (used for validation). 

        internal Type RootType
        {
            get { return _rootType; } 
        }
 
 

#endregion Helpers 

#region Data

        private ParserContext                   _parserContext; 

        private Stack  _optimizableElementState; 
 
        private BamlMapTable                    _mapTable;
        private OptimizedTemplateContentHelper  _optimizedTemplateContentHelper; 
        private FrameworkTemplate               _frameworkTemplate;
        private ShareableRecordState            _currentState;
        private bool                            _searchingForName;
 
        private BamlRecord                      _unsharedContent;
        private FrugalObjectList      _sharedProperties; 
 
        private Stack                           _nameStack;
        private Collection          _unsharedContentCollection; 
        private TypeConvertContext              _typeConvertContext;
        private BamlRecord                      _bamlRecordsSubtreeStart;

        private Type                            _rootType; // Type of the content's root element 
        private int                             _positionOptimizableElementState; // Used by StartShreableTree
 
        private int                             _generatedNameIndex = 0; 

#endregion Data 
    }

}
 

// 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