File: System\Windows\TemplateContent.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Xaml;
using System.Xaml.Schema;
using System.Xaml.Permissions;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Diagnostics;
using System.Windows.Markup;
using System.Globalization;
using MS.Utility;
using System.ComponentModel;
using System.Collections;
using System.Collections.Specialized;
using MS.Internal.Xaml.Context;
using System.Windows.Baml2006;
 
namespace System.Windows
{
    //TemplateContent is meant to hold any data that is needed during TemplateLoad and TemplateApply.
    // _templateLoadData holds all other data.
    [XamlDeferLoad(typeof(TemplateContentLoader), typeof(FrameworkElement))]
    public class TemplateContent
    {
        internal class Frame : XamlFrame
        {
            private FrugalObjectList<System.Xaml.NamespaceDeclaration> _namespaces;
            private System.Xaml.XamlType _xamlType;
 
            public Frame() { }
 
            public XamlType Type
            {
                get { return _xamlType; }
                set
                {
                    // can't change the type (except from null)
                    Debug.Assert(_xamlType == null);
 
                    _xamlType = value;
                }
            }
 
            public XamlMember Property { get; set; }
            public string Name { get; set; }
            public bool NameSet { get; set; }
            public bool IsInNameScope { get; set; }
            public bool IsInStyleOrTemplate { get; set; }
            public object Instance { get; set; }
 
            //ContentPresenter
            public bool ContentSet { get; set; }
            public bool ContentSourceSet { get; set; }
            public String ContentSource { get; set; }
            public bool ContentTemplateSet { get; set; }
            public bool ContentTemplateSelectorSet { get; set; }
            public bool ContentStringFormatSet { get; set; }
 
            //GridViewRowPresenter
            public bool ColumnsSet { get; set; }
 
            public override void Reset()
            {
                _xamlType = null;
                Property = null;
                Name = null;
                NameSet = false;
                IsInNameScope = false;
                Instance = null;
                ContentSet = false;
                ContentSourceSet = false;
                ContentSource = null;
                ContentTemplateSet = false;
                ContentTemplateSelectorSet = false;
                ContentStringFormatSet = false;
                IsInNameScope = false;
                if (HasNamespaces)
                {
                    _namespaces = null;
                }
            }
 
            public FrugalObjectList<System.Xaml.NamespaceDeclaration> Namespaces
            {
                get
                {
                    if (_namespaces == null)
                    {
                        _namespaces = new FrugalObjectList<System.Xaml.NamespaceDeclaration>();
                    }
                    return _namespaces;
                }
            }
 
            public bool HasNamespaces { get { return _namespaces != null && _namespaces.Count > 0; } }
 
            public override string ToString()
            {
                string type = (this.Type == null) ? String.Empty : this.Type.Name;
                string prop = (this.Property == null) ? "-" : this.Property.Name;
                string inst = (Instance == null) ? "-" : "*";
                string res = $"{type}.{prop} inst={inst}";
                return res;
            }
        }
 
        internal class StackOfFrames : XamlContextStack<Frame>
        {
            public StackOfFrames() : base(()=>new Frame()) { }
 
            public void Push(System.Xaml.XamlType xamlType, string name)
            {
                bool isInNameScope = false;
                bool isInStyleOrTemplate = false;
 
                if (Depth > 0)
                {
                    isInNameScope = CurrentFrame.IsInNameScope || (CurrentFrame.Type != null && FrameworkTemplate.IsNameScope(CurrentFrame.Type));
                    isInStyleOrTemplate = CurrentFrame.IsInStyleOrTemplate ||
                        (CurrentFrame.Type != null &&
                            (typeof(FrameworkTemplate).IsAssignableFrom(CurrentFrame.Type.UnderlyingType) ||
                             typeof(Style).IsAssignableFrom(CurrentFrame.Type.UnderlyingType)));
                }
 
                if (Depth == 0 || CurrentFrame.Type != null)
                {
                    base.PushScope();
                }
 
                CurrentFrame.Type = xamlType;
                CurrentFrame.Name = name;
                CurrentFrame.IsInNameScope = isInNameScope;
                CurrentFrame.IsInStyleOrTemplate = isInStyleOrTemplate;
            }
 
            public void AddNamespace(System.Xaml.NamespaceDeclaration nsd)
            {
                bool isInNameScope = false;
                bool isInStyleOrTemplate = false;
 
                if (Depth > 0)
                {
                    isInNameScope = CurrentFrame.IsInNameScope || (CurrentFrame.Type != null && FrameworkTemplate.IsNameScope(CurrentFrame.Type));
                    isInStyleOrTemplate = CurrentFrame.IsInStyleOrTemplate ||
                        (CurrentFrame.Type != null &&
                            (typeof(FrameworkTemplate).IsAssignableFrom(CurrentFrame.Type.UnderlyingType) ||
                             typeof(Style).IsAssignableFrom(CurrentFrame.Type.UnderlyingType)));
                }
 
                if (Depth == 0 || CurrentFrame.Type != null)
                {
                    base.PushScope();
                }
 
                CurrentFrame.Namespaces.Add(nsd);
                CurrentFrame.IsInNameScope = isInNameScope;
                CurrentFrame.IsInStyleOrTemplate = isInStyleOrTemplate;
            }
 
            public FrugalObjectList<System.Xaml.NamespaceDeclaration> InScopeNamespaces
            {
                get
                {
                    FrugalObjectList<System.Xaml.NamespaceDeclaration> allNamespaces = null;
                    Frame iteratorFrame = this.CurrentFrame;
 
                    while (iteratorFrame != null)
                    {
                        if (iteratorFrame.HasNamespaces)
                        {
                            if (allNamespaces == null)  // late allocation cause there is often nothing.
                            {
                                allNamespaces = new FrugalObjectList<System.Xaml.NamespaceDeclaration>();
                            }
                            for (int idx = 0; idx < iteratorFrame.Namespaces.Count; idx++)
                            {
                                allNamespaces.Add(iteratorFrame.Namespaces[idx]);
                            }
                        }
                        iteratorFrame = (Frame)iteratorFrame.Previous;
                    }
                    return allNamespaces;
                }
            }
        }
 
        internal TemplateContent(System.Xaml.XamlReader xamlReader, IXamlObjectWriterFactory factory,
            IServiceProvider context)
        {
            TemplateLoadData = new TemplateLoadData();
            ObjectWriterFactory = factory;
            SchemaContext = xamlReader.SchemaContext;
            ObjectWriterParentSettings = factory.GetParentSettings();
 
            XamlAccessLevel accessLevel = ObjectWriterParentSettings.AccessLevel;
            TemplateLoadData.Reader = xamlReader;
 
            Initialize(context);
        }
 
        private void Initialize(IServiceProvider context)
        {
            XamlObjectWriterSettings settings = System.Windows.Markup.XamlReader.
                CreateObjectWriterSettings(ObjectWriterParentSettings);
            settings.AfterBeginInitHandler = delegate(object sender, System.Xaml.XamlObjectEventArgs args)
            {
                //In several situations this even will happen with Stack == null.
                //If this event was on the XOW, perhaps we could stop listening in some circumstances?
                if (Stack != null && Stack.Depth > 0)
                {
                    Stack.CurrentFrame.Instance = args.Instance;
                }
            };
            settings.SkipProvideValueOnRoot = true;
            TemplateLoadData.ObjectWriter = ObjectWriterFactory.GetXamlObjectWriter(settings);
            TemplateLoadData.ServiceProviderWrapper = new ServiceProviderWrapper(context, SchemaContext);
 
            IRootObjectProvider irop = context.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider;
            if (irop != null)
            {
                TemplateLoadData.RootObject = irop.RootObject;
            }
        }
 
        // This needs to take the XamlReader passed in and sort it into things that
        // can be shared and can't be shared.  Anything that can't be shared
        // needs to be stored away so that we can instantiate at template load time.
        // Shared values need to be stored into the shared value tables.
        internal void ParseXaml()
        {
            Debug.Assert(TemplateLoadData.Reader != null);
            StackOfFrames stack = new StackOfFrames();
 
            TemplateLoadData.ServiceProviderWrapper.Frames = stack;
 
            OwnerTemplate.StyleConnector = TemplateLoadData.RootObject as IStyleConnector;
            TemplateLoadData.RootObject = null;
 
            List<PropertyValue> sharedProperties = new List<PropertyValue>();
 
            int nameNumber = 1;
            ParseTree(stack, sharedProperties, ref nameNumber);
 
            // Items panel templates have special rules
            if (OwnerTemplate is ItemsPanelTemplate)
            {
                PropertyValue pv = new PropertyValue();
                pv.ValueType = PropertyValueType.Set;
                pv.ChildName = TemplateLoadData.RootName;
                pv.ValueInternal = true;
                pv.Property = Panel.IsItemsHostProperty;
 
                sharedProperties.Add(pv);
            }
 
            // Add all the shared properties to the special table
            for (int i = 0; i < sharedProperties.Count; i++)
            {
                PropertyValue value = sharedProperties[i];
 
                if (value.ValueInternal is TemplateBindingExtension)  // Use ValueInternal to avoid creating deferred resource references
                {
                    value.ValueType = PropertyValueType.TemplateBinding;
                }
                else if (value.ValueInternal is DynamicResourceExtension) // Use ValueInternal to avoid creating deferred resource references
                {
                    DynamicResourceExtension dynamicResource = value.Value as DynamicResourceExtension;
 
                    value.ValueType = PropertyValueType.Resource;
                    value.ValueInternal = dynamicResource.ResourceKey;
                }
                else
                {
                    StyleHelper.SealIfSealable(value.ValueInternal);
                }
 
                StyleHelper.UpdateTables(ref value, ref OwnerTemplate.ChildRecordFromChildIndex, ref OwnerTemplate.TriggerSourceRecordFromChildIndex,
                    ref OwnerTemplate.ResourceDependents, ref OwnerTemplate._dataTriggerRecordFromBinding, OwnerTemplate.ChildIndexFromChildName, ref OwnerTemplate._hasInstanceValues);
            }
 
            //We don't need to use this object writer anymore so let's clear it out.
            TemplateLoadData.ObjectWriter = null;
        }
 
        internal System.Xaml.XamlReader PlayXaml()
        {
            return _xamlNodeList.GetReader();
        }
 
        //Called by FrameworkTemplate.Seal() to let go of the data used for Template Load.
        internal void ResetTemplateLoadData()
        {
            TemplateLoadData = null;
        }
 
        //+------------------------------------------------------------------------------------------
        //
        //  UpdateSharedList
        //
        //  Update the last items on the shared DependencyProperty list with the
        //  name of the current element.
        //
        //+------------------------------------------------------------------------------------------
        private void UpdateSharedPropertyNames(string name, List<PropertyValue> sharedProperties, XamlType type)
        {
#if DEBUG
            int lastIndex = OwnerTemplate.LastChildIndex;
#endif
 
            // Generate an index for this name
            int childIndex = StyleHelper.CreateChildIndexFromChildName(name, OwnerTemplate);
 
            OwnerTemplate.ChildNames.Add(name);
            OwnerTemplate.ChildTypeFromChildIndex.Add(childIndex, type.UnderlyingType);
 
#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--)
            {
                PropertyValue sdp = sharedProperties[i];
 
                if (sdp.ChildName == null)
                {
                    sdp.ChildName = name;
                }
                else
                {
                    break;
                }
 
                sharedProperties[i] = sdp;
            }
        }
 
        private void ParseTree(
            StackOfFrames stack,
            List<PropertyValue> sharedProperties,
            ref int nameNumber)
        {
            ParseNodes(stack, sharedProperties, ref nameNumber);
        }
 
        private void ParseNodes(
            StackOfFrames stack,
            List<PropertyValue> sharedProperties,
            ref int nameNumber)
        {
            _xamlNodeList = new XamlNodeList(SchemaContext);
            System.Xaml.XamlWriter writer = _xamlNodeList.Writer;
            System.Xaml.XamlReader reader = TemplateLoadData.Reader;
 
            // Prepare to provide source info if needed
            IXamlLineInfoConsumer lineInfoConsumer = null;
            IXamlLineInfo lineInfo = null;
            if (XamlSourceInfoHelper.IsXamlSourceInfoEnabled)
            {
                lineInfo = reader as IXamlLineInfo;
                if (lineInfo != null)
                {
                    lineInfoConsumer = writer as IXamlLineInfoConsumer;
                }
            }
 
            while (reader.Read())
            {
                if (lineInfoConsumer != null)
                {
                    lineInfoConsumer.SetLineInfo(lineInfo.LineNumber, lineInfo.LinePosition);
                }
 
                object newValue;
                bool reProcessOnApply = ParseNode(reader, stack, sharedProperties, ref nameNumber, out newValue);
                if (reProcessOnApply)
                {
                    if (newValue == DependencyProperty.UnsetValue)
                    {
                        writer.WriteNode(reader);
                    }
                    else
                    {
                        writer.WriteValue(newValue);
                    }
                }
            }
            writer.Close();
            TemplateLoadData.Reader = null;
        }
 
        // Returns true if the node should be re-processed on template apply. If the value is
        // shareable, the node doesn't need to be reprocessed, so we return false.
        private bool ParseNode(System.Xaml.XamlReader xamlReader,
            StackOfFrames stack,
            List<PropertyValue> sharedProperties,
            ref int nameNumber,
            out object newValue)
        {
            newValue = DependencyProperty.UnsetValue;
            switch (xamlReader.NodeType)
            {
                case System.Xaml.XamlNodeType.StartObject:
                    {
                        // Process the load-time binding of StaticResources.
                        // SR usage in RD's will be instance Values coming from the BAML reader.
                        // SR in node list form are from inline templates.  (or XML text)
                        // V3 also hard codes type EQUALITY against StaticResourceExtension
                        if (xamlReader.Type.UnderlyingType == typeof(StaticResourceExtension))
                        {
                            // Use the shared XamlObjectWriter but clear the state first
                            XamlObjectWriter writer = TemplateLoadData.ObjectWriter;
                            writer.Clear();
                            WriteNamespaces(writer, stack.InScopeNamespaces, null);
 
                            // newValue is an out parameter that will change the value in the processed node stream.
                            newValue = LoadTimeBindUnshareableStaticResource(xamlReader, writer);
                            return true;
                        }
 
                        // Check to see if the parent object needs to have the name set
                        if (stack.Depth > 0 &&
                            stack.CurrentFrame.NameSet == false &&
                            stack.CurrentFrame.Type != null &&
                            !stack.CurrentFrame.IsInNameScope &&
                            !stack.CurrentFrame.IsInStyleOrTemplate)
                        {
                            // FEs and FCEs need to be added to the name to index map
                            if (typeof(FrameworkElement).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType) ||
                                typeof(FrameworkContentElement).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType))
                            {
                                // All FEs and FCEs must have a name.  We assign a default if there was no name provided
                                string name = $"{nameNumber++.ToString(CultureInfo.InvariantCulture)}_T";
                                UpdateSharedPropertyNames(name, sharedProperties, stack.CurrentFrame.Type);
                                stack.CurrentFrame.Name = name;
                            }
                            stack.CurrentFrame.NameSet = true;
                        }
 
                        if (RootType == null)
                        {
                            RootType = xamlReader.Type;
                        }
                        stack.Push(xamlReader.Type, null);
                    }
                    break;
                case System.Xaml.XamlNodeType.GetObject:
                    {
                        // Check to see if the parent object needs to have the name set
                        if (stack.Depth > 0 &&
                            stack.CurrentFrame.NameSet == false &&
                            stack.CurrentFrame.Type != null &&
                            !stack.CurrentFrame.IsInNameScope &&
                            !stack.CurrentFrame.IsInStyleOrTemplate)
                        {
                            // FEs and FCEs need to be added to the name to index map
                            if (typeof(FrameworkElement).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType) ||
                                typeof(FrameworkContentElement).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType))
                            {
                                // All FEs and FCEs must have a name.  We assign a default if there was no name provided
                                string name = $"{nameNumber++.ToString(CultureInfo.InvariantCulture)}_T";
                                UpdateSharedPropertyNames(name, sharedProperties, stack.CurrentFrame.Type);
                                stack.CurrentFrame.Name = name;
                            }
                            stack.CurrentFrame.NameSet = true;
                        }
 
                        XamlType type = stack.CurrentFrame.Property.Type;
                        if (RootType == null)
                        {
                            RootType = type;
                        }
                        stack.Push(type, null);
                    }
                    break;
                case System.Xaml.XamlNodeType.EndObject:
                    if (!stack.CurrentFrame.IsInStyleOrTemplate)
                    {
                        if (stack.CurrentFrame.NameSet == false && !stack.CurrentFrame.IsInNameScope)
                        {
                            // FEs and FCEs need to be added to the name to index map
                            if (typeof(FrameworkElement).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType) ||
                                typeof(FrameworkContentElement).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType))
                            {
                                // All FEs and FCEs must have a name.  We assign a default if there was no name provided
                                string name = $"{nameNumber++.ToString(CultureInfo.InvariantCulture)}_T";
                                UpdateSharedPropertyNames(name, sharedProperties, stack.CurrentFrame.Type);
                                stack.CurrentFrame.Name = name;
                            }
                            stack.CurrentFrame.NameSet = true;
                        }
 
                        if (TemplateLoadData.RootName == null && stack.Depth == 1)
                        {
                            TemplateLoadData.RootName = stack.CurrentFrame.Name;
                        }
 
                        // ContentPresenters have special rules for aliasing Content
                        if (typeof(ContentPresenter).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType))
                        {
                            AutoAliasContentPresenter(
                                OwnerTemplate.TargetTypeInternal,
                                stack.CurrentFrame.ContentSource,
                                stack.CurrentFrame.Name,
                                ref OwnerTemplate.ChildRecordFromChildIndex,
                                ref OwnerTemplate.TriggerSourceRecordFromChildIndex,
                                ref OwnerTemplate.ResourceDependents,
                                ref OwnerTemplate._dataTriggerRecordFromBinding,
                                ref OwnerTemplate._hasInstanceValues,
                                OwnerTemplate.ChildIndexFromChildName,
                                stack.CurrentFrame.ContentSet,
                                stack.CurrentFrame.ContentSourceSet,
                                stack.CurrentFrame.ContentTemplateSet,
                                stack.CurrentFrame.ContentTemplateSelectorSet,
                                stack.CurrentFrame.ContentStringFormatSet
                                );
                        }
 
                        // GridViewRowPresenters have special rules for aliasing Content
                        if (typeof(GridViewRowPresenter).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType))
                        {
                            AutoAliasGridViewRowPresenter(
                                OwnerTemplate.TargetTypeInternal,
                                stack.CurrentFrame.ContentSource,
                                stack.CurrentFrame.Name,
                                ref OwnerTemplate.ChildRecordFromChildIndex,
                                ref OwnerTemplate.TriggerSourceRecordFromChildIndex,
                                ref OwnerTemplate.ResourceDependents,
                                ref OwnerTemplate._dataTriggerRecordFromBinding,
                                ref OwnerTemplate._hasInstanceValues,
                                OwnerTemplate.ChildIndexFromChildName,
                                stack.CurrentFrame.ContentSet,
                                stack.CurrentFrame.ColumnsSet
                                );
                        }
                    }
 
                    stack.PopScope();
                    break;
 
                case System.Xaml.XamlNodeType.StartMember:
                    stack.CurrentFrame.Property = xamlReader.Member;
 
                    if (!stack.CurrentFrame.IsInStyleOrTemplate)
                    {
 
                        // Need to know if these properties are set for
                        // autoaliasing.
                        if (typeof(GridViewRowPresenter).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType))
                        {
                            if (xamlReader.Member.Name == "Content")
                                stack.CurrentFrame.ContentSet = true;
                            else if (xamlReader.Member.Name == "Columns")
                                stack.CurrentFrame.ColumnsSet = true;
                        }
                        else if (typeof(ContentPresenter).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType))
                        {
                            if (xamlReader.Member.Name == "Content")
                                stack.CurrentFrame.ContentSet = true;
                            else if (xamlReader.Member.Name == "ContentTemplate")
                                stack.CurrentFrame.ContentTemplateSet = true;
                            else if (xamlReader.Member.Name == "ContentTemplateSelector")
                                stack.CurrentFrame.ContentTemplateSelectorSet = true;
                            else if (xamlReader.Member.Name == "ContentStringFormat")
                                stack.CurrentFrame.ContentStringFormatSet = true;
                            else if (xamlReader.Member.Name == "ContentSource")
                                stack.CurrentFrame.ContentSourceSet = true;
                        }
 
                        if (!stack.CurrentFrame.IsInNameScope &&
                            xamlReader.Member.IsDirective == false)
                        {
 
                            // Try to see if the property is shareable
                            PropertyValue? sharedValue;
                            var iReader = xamlReader as IXamlIndexingReader;
                            Debug.Assert(iReader != null, "Template's Reader is not a Indexing Reader");
 
                            bool sharable = false;
                            int savedIdx = iReader.CurrentIndex;
 
                            try
                            {
                                sharable = TrySharingProperty(xamlReader,
                                        stack.CurrentFrame.Type,
                                        stack.CurrentFrame.Name,
                                        stack.InScopeNamespaces,
                                        out sharedValue);
                            }
                            catch
                            {
                                sharable = false;
                                sharedValue = null;
                            }
 
                            // Property is NOT shareable.
                            // Back-up and add the unsharable section.
                            if (!sharable)
                            {
                                iReader.CurrentIndex = savedIdx;
                                break;
                            }
                            else
                            {
                                // Value can be shared.
                                // Add it to the shared properties list
 
                                Debug.Assert(sharedValue != null);
                                sharedProperties.Add(sharedValue.Value);
 
                                if (typeof(GridViewRowPresenter).
                                    IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType) ||
                                    typeof(ContentPresenter).
                                    IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType))
                                {
                                    if (sharedValue.Value.Property.Name == "ContentSource")
                                    {
                                        stack.CurrentFrame.ContentSource =
                                            sharedValue.Value.ValueInternal as String;
 
                                        // Consider throwing the exception
                                        // ContentSource can only be a String or null.  If it is anything
                                        // else, we should fall back to the default by pretending
                                        // the property was never set.
                                        if (!(sharedValue.Value.ValueInternal is String) &&
                                            sharedValue.Value.ValueInternal != null)
                                        {
                                            stack.CurrentFrame.ContentSourceSet = false;
                                        }
                                    }
                                }
                            }
                            return false;
                        }
                    }
                    break;
 
                case System.Xaml.XamlNodeType.EndMember:
                    stack.CurrentFrame.Property = null;
                    break;
 
                case System.Xaml.XamlNodeType.Value:
                    if (!stack.CurrentFrame.IsInStyleOrTemplate)
                    {
                        if (FrameworkTemplate.IsNameProperty(stack.CurrentFrame.Property, stack.CurrentFrame.Type))
                        {
                            string name = xamlReader.Value as String;
 
                            stack.CurrentFrame.Name = name;
                            stack.CurrentFrame.NameSet = true;
 
                            if (TemplateLoadData.RootName == null)
                            {
                                TemplateLoadData.RootName = name;
                            }
 
                            if (!stack.CurrentFrame.IsInNameScope)
                            {
                                // FEs and FCEs need to be added to the name to index map
                                if (typeof(FrameworkElement).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType) ||
                                    typeof(FrameworkContentElement).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType))
                                {
                                    TemplateLoadData.NamedTypes.Add(name, stack.CurrentFrame.Type);
 
                                    // All FEs and FCEs must have a name.  We assign a default if there was no name provided
                                    UpdateSharedPropertyNames(name, sharedProperties, stack.CurrentFrame.Type);
                                }
                            }
                        }
 
                        if (typeof(ContentPresenter).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType)
                            && stack.CurrentFrame.Property.Name == "ContentSource")
                        {
                            stack.CurrentFrame.ContentSource = xamlReader.Value as String;
                        }
                    }
                    object value = xamlReader.Value;
                    StaticResourceExtension staticResource = value as StaticResourceExtension;
                    // Process the load-time binding of StaticResources.
                    // If this is a simple inline template then the StaticResources will be StaticResourcesExtensions
                    // [They also might be node-lists, see LoadTimeBindUnshareableStaticResource()]
                    // and we do a full search for the location of the value and hold a deferred reference to it.
                    // If the template was in a Resource Dictionary, the RD would have already replaced the
                    // StaticResource with a StaticResourceHolder and we need to do a "live stack only" walk
                    // to look for RD's that might be closer, for better values.
                    if (staticResource != null)
                    {
                        object obj = null;
 
                        // Inline Template case:
                        if (staticResource.GetType() == typeof(StaticResourceExtension))
                        {
                            obj = staticResource.TryProvideValueInternal(TemplateLoadData.ServiceProviderWrapper, true/*allowDeferredReference*/, true/*mustReturnDeferredResourceReference*/);
                        }
 
                        // Template in a Resource Dictionary entry case:
                        else if (staticResource.GetType() == typeof(StaticResourceHolder))
                        {
                            obj = staticResource.FindResourceInDeferredContent(TemplateLoadData.ServiceProviderWrapper, true/*allowDeferredReference*/, false/*mustReturnDeferredResourceReference*/);
                            if (obj == DependencyProperty.UnsetValue)
                            {
                                obj = null;  // value is only interesting if it improves the previous value.
                            }
                        }
                        if (obj != null)
                        {
                            var deferredResourceReference = obj as DeferredResourceReference;
 
                            // newValue is an out parameter that will change the value in the processed node stream.
                            newValue = new StaticResourceHolder(staticResource.ResourceKey, deferredResourceReference);
                        }
                    }
                    break;
 
                case System.Xaml.XamlNodeType.NamespaceDeclaration:
 
                    // *** This code assumes that NamespaceDeclarations can only come before [Start|Get]Object. ***
                    // This needs to be updated in the future to support it before properties & Values.
 
                    if (!stack.CurrentFrame.IsInStyleOrTemplate)
                    {
                        // Check to see if the parent object needs to have the name set
                        if (stack.Depth > 0 && stack.CurrentFrame.NameSet == false && stack.CurrentFrame.Type != null && !stack.CurrentFrame.IsInNameScope)
                        {
                            // FEs and FCEs need to be added to the name to index map
                            if (typeof(FrameworkElement).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType) ||
                                typeof(FrameworkContentElement).IsAssignableFrom(stack.CurrentFrame.Type.UnderlyingType))
                            {
                                // All FEs and FCEs must have a name.  We assign a default if there was no name provided
                                string name = $"{nameNumber++.ToString(CultureInfo.InvariantCulture)}_T";
                                UpdateSharedPropertyNames(name, sharedProperties, stack.CurrentFrame.Type);
                                stack.CurrentFrame.Name = name;
                            }
                            stack.CurrentFrame.NameSet = true;
                        }
                    }
 
                    stack.AddNamespace(xamlReader.Namespace);
                    break;
                case System.Xaml.XamlNodeType.None:
                    break;
            }
            return true;
        }
 
        private StaticResourceExtension LoadTimeBindUnshareableStaticResource(Xaml.XamlReader xamlReader, XamlObjectWriter writer)
        {
            Debug.Assert(xamlReader.NodeType == Xaml.XamlNodeType.StartObject);
            Debug.Assert(xamlReader.Type.UnderlyingType == typeof(StaticResourceExtension));
 
            // Loop through the nodes and create the StaticResource.  Since objects could be nested inside the SRE, we need to keep
            // track of the number of start and end objects.
            int elementDepth = 0;
            do
            {
                writer.WriteNode(xamlReader);
                switch (xamlReader.NodeType)
                {
                    case Xaml.XamlNodeType.StartObject:
                    case Xaml.XamlNodeType.GetObject:
                        elementDepth++;
                        break;
                    case Xaml.XamlNodeType.EndObject:
                        elementDepth--;
                        break;
                }
            }
            while (elementDepth > 0 && xamlReader.Read());
 
            StaticResourceExtension resource = writer.Result as StaticResourceExtension;
            Debug.Assert(resource != null);
 
            // If the StaicResource was in NodeList form then it would not have been pre-resolved.
            // So do a full walk now, not a Live-Stack only.
            // Resolve the StaticResource value including lookup to the app and the theme
            DeferredResourceReference value = (DeferredResourceReference)resource.TryProvideValueInternal(TemplateLoadData.ServiceProviderWrapper, true/*allowDeferredReference*/, true/*mustReturnDeferredResourceReference*/);
 
            // Return the value that will be written out the unshareable node list;
            return new StaticResourceHolder(resource.ResourceKey, value);
        }
 
        // Tries to see if the property can be shared.  Returns true property is shared.
        // Caller is responsible for bookmarking.
        //
        // Only property values can be shared.  We try to share anything that is a Freezable,
        // ME, Style, Template.  However, if the parent type is named, we can't share anything.
        // However, TemplateBindingExtension are ALWAYS shared
        private bool TrySharingProperty(System.Xaml.XamlReader xamlReader,
            XamlType parentType,
            string parentName,
            FrugalObjectList<System.Xaml.NamespaceDeclaration> previousNamespaces,
            out PropertyValue? sharedValue)
        {
            Debug.Assert(xamlReader.NodeType == System.Xaml.XamlNodeType.StartMember);
            // All DependencyPropertys are wrapped in WpfXamlMembers.  If it's not a WpfXamlMember, it's not a DependencyProperty
            WpfXamlMember xamlProperty = xamlReader.Member as WpfXamlMember;
            if (xamlProperty == null)
            {
                sharedValue = null;
                return false;
            }
            DependencyProperty property = xamlProperty.DependencyProperty;
 
            // We can only share DPs.  Return the node pipe with just the SP in it
            if (property == null)
            {
                sharedValue = null;
                return false;
            }
            // Also, we cannot share the name property
            if (xamlReader.Member == parentType.GetAliasedProperty(XamlLanguage.Name))
            {
                sharedValue = null;
                return false;
            }
            // We can only share properties on FEs and FCEs
            if (!typeof(FrameworkElement).IsAssignableFrom(parentType.UnderlyingType) &&
                 !typeof(FrameworkContentElement).IsAssignableFrom(parentType.UnderlyingType))
            {
                sharedValue = null;
                return false;
            }
 
            // Check if the value is shareable.
            // We are in a StartMember so we assume there is another node to read.
            xamlReader.Read();
 
            // Check if the value is shareable.
            if (xamlReader.NodeType == System.Xaml.XamlNodeType.Value)
            {
                // Null would be shareable but when 4.0 shipped a null Value caused
                // an exception to be thrown here.
                //    xamlReader.Value.GetType();
                // Throwning an exceptions will mark item as unshareable.  So for compability,
                // Null is not shareable.
                // But the much more common case of a NullExtension object is sharable.
                if (xamlReader.Value == null)
                {
                    sharedValue = null;
                    return false;
                }
                Type typeofValue = xamlReader.Value.GetType();
                if (!CheckSpecialCasesShareable(typeofValue, property))
                {
                    sharedValue = null;
                    return false;
                }
                if (!(xamlReader.Value is String))
                {
                    return TrySharingValue(property, xamlReader.Value,
                        parentName, xamlReader, true, out sharedValue);
                }
                else
                {
                    object value = xamlReader.Value;
 
                    TypeConverter converter = null;
                    if (xamlProperty.TypeConverter != null)
                    {
                        converter = xamlProperty.TypeConverter.ConverterInstance;
                    }
                    else if (xamlProperty.Type.TypeConverter != null)
                    {
                        converter = xamlProperty.Type.TypeConverter.ConverterInstance;
                    }
 
                    if (converter != null)
                    {
                        value = converter.ConvertFrom(TemplateLoadData.ServiceProviderWrapper, CultureInfo.InvariantCulture, value);
                    }
 
                    return TrySharingValue(property, value, parentName, xamlReader, true, out sharedValue);
                }
            }
            else if (xamlReader.NodeType == System.Xaml.XamlNodeType.StartObject
                || xamlReader.NodeType == System.Xaml.XamlNodeType.NamespaceDeclaration)
            {
                FrugalObjectList<System.Xaml.NamespaceDeclaration> localNamespaces = null;
                if (xamlReader.NodeType == System.Xaml.XamlNodeType.NamespaceDeclaration)
                {
                    localNamespaces = new FrugalObjectList<Xaml.NamespaceDeclaration>();
                    while (xamlReader.NodeType == System.Xaml.XamlNodeType.NamespaceDeclaration)
                    {
                        localNamespaces.Add(xamlReader.Namespace);
                        xamlReader.Read();
                    }
                }
 
                Debug.Assert(xamlReader.NodeType == System.Xaml.XamlNodeType.StartObject);
 
                Type typeofValue = xamlReader.Type.UnderlyingType;
                if (!CheckSpecialCasesShareable(typeofValue, property))
                {
                    sharedValue = null;
                    return false;
                }
                if (!IsTypeShareable(xamlReader.Type.UnderlyingType))
                {
                    sharedValue = null;
                    return false;
                }
                else
                {
                    // Keep track of the number of SOs and EOs
                    // Perf note: This stack may be sharable if this gets hit multiple times per TemplateContent.
                    StackOfFrames frames = new StackOfFrames();
                    frames.Push(xamlReader.Type, null);
 
                    bool insideTemplate = false;
                    bool insideStyle = false;
 
                    // We don't care about named elements inside of Templates or Styles.  We allow it to just work.
                    if (typeof(FrameworkTemplate).IsAssignableFrom(xamlReader.Type.UnderlyingType))
                    {
                        insideTemplate = true;
                        Stack = frames;
                    }
                    else if (typeof(Style).IsAssignableFrom(xamlReader.Type.UnderlyingType))
                    {
                        insideStyle = true;
                        Stack = frames;
                    }
 
                    try
                    {
 
                        //Setup ObjectWriter to be able to create the right values
                        XamlObjectWriter writer = TemplateLoadData.ObjectWriter;
                        writer.Clear();
                        WriteNamespaces(writer, previousNamespaces, localNamespaces);
                        writer.WriteNode(xamlReader);
 
                        bool done = false;
                        while (!done && xamlReader.Read())
                        {
                            SkipFreeze(xamlReader);
                            writer.WriteNode(xamlReader);
                            switch (xamlReader.NodeType)
                            {
                                case System.Xaml.XamlNodeType.StartObject:
                                    if (typeof(StaticResourceExtension).IsAssignableFrom(xamlReader.Type.UnderlyingType))
                                    {
                                        sharedValue = null;
                                        return false;
                                    }
                                    frames.Push(xamlReader.Type, null);
                                    break;
 
                                case System.Xaml.XamlNodeType.GetObject:
                                    XamlType type = frames.CurrentFrame.Property.Type;
                                    frames.Push(type, null);
                                    break;
 
                                case System.Xaml.XamlNodeType.EndObject:
                                    if (frames.Depth == 1)
                                    {
                                        return TrySharingValue(property, writer.Result, parentName,
                                            xamlReader, true, out sharedValue);
                                    }
                                    frames.PopScope();
                                    break;
 
                                case System.Xaml.XamlNodeType.StartMember:
                                    // Anything that is named cannot be shared
                                    if (!(insideStyle || insideTemplate) && FrameworkTemplate.IsNameProperty(xamlReader.Member, frames.CurrentFrame.Type))
                                    {
                                        done = true;
                                        break;
                                    }
                                    frames.CurrentFrame.Property = xamlReader.Member;
                                    break;
 
                                case System.Xaml.XamlNodeType.Value:
                                    if (xamlReader.Value != null && typeof(StaticResourceExtension).IsAssignableFrom(xamlReader.Value.GetType()))
                                    {
                                        sharedValue = null;
                                        return false;
                                    }
                                    // We want to wire EventSetters for Styles but not wire
                                    // events inside of a FramewokrTemplate
                                    if (!insideTemplate && frames.CurrentFrame.Property == XamlLanguage.ConnectionId)
                                    {
                                        if (OwnerTemplate.StyleConnector != null)
                                        {
                                            OwnerTemplate.StyleConnector.Connect((int)xamlReader.Value, frames.CurrentFrame.Instance);
                                        }
                                    }
                                    break;
                            }
                        }
 
                        // We've broken out of the while loop and haven't returned
                        // The property is NOT shareable.
                        sharedValue = null;
                        return false;
                    }
                    finally
                    {
                        Stack = null;
                    }
                }
            }
            else if (xamlReader.NodeType == System.Xaml.XamlNodeType.GetObject)
            {
                sharedValue = null;
                return false;
            }
            else
            {
                // Should never happen
                throw new System.Windows.Markup.XamlParseException(SR.ParserUnexpectedEndEle);
            }
        }
 
        private static bool CheckSpecialCasesShareable(Type typeofValue, DependencyProperty property)
        {
            if (typeofValue != typeof(DynamicResourceExtension)
                && typeofValue != typeof(TemplateBindingExtension)
                && typeofValue != typeof(TypeExtension)
                && typeofValue != typeof(StaticExtension))
            {
                // Do not share in the case property type <: IList, Array, IDictionary to maintain compat with v3
                // They wrapped with BamlCollectionHolder in these 3 cases so the value isn't shared.
                if (typeof(IList).IsAssignableFrom(property.PropertyType))
                {
                    return false;
                }
                if (property.PropertyType.IsArray)
                {
                    return false;
                }
                if (typeof(IDictionary).IsAssignableFrom(property.PropertyType))
                {
                    return false;
                }
            }
            return true;
        }
 
        private static bool IsFreezableDirective(System.Xaml.XamlReader reader)
        {
            System.Xaml.XamlNodeType nodeType = reader.NodeType;
            if (nodeType == System.Xaml.XamlNodeType.StartMember)
            {
                System.Xaml.XamlMember member = reader.Member;
                return (member.IsUnknown && member.IsDirective && member.Name == "Freeze");
            }
            return false;
        }
 
        private static void SkipFreeze(System.Xaml.XamlReader reader)
        {
            if (IsFreezableDirective(reader))
            {
                reader.Read();  // V
                reader.Read();  // EM
                reader.Read();  // Next
            }
        }
 
        private bool TrySharingValue(DependencyProperty property,
                                     object value,
                                     string parentName,
                                     System.Xaml.XamlReader xamlReader,
                                     bool allowRecursive,
                                     out PropertyValue? sharedValue)
        {
            sharedValue = null;
 
            // Null is sharable.
            if (value != null && !IsTypeShareable(value.GetType()))
            {
                return false;
            }
 
            bool isValueShareable = true;
 
            if (value is Freezable)
            {
                // Check if it's a freezable and we can freeze it
                Freezable freezable = value as Freezable;
                if (freezable != null)
                {
                    if (freezable.CanFreeze)
                    {
                        freezable.Freeze();
                    }
                    else
                    {
                        // Object is not freezable, which means its
                        // not shareable.
                        isValueShareable = false;
                    }
                }
            }
            else if (value is CollectionViewSource)
            {
                CollectionViewSource viewSource = value as CollectionViewSource;
                if (viewSource != null)
                {
                    isValueShareable = viewSource.IsShareableInTemplate();
                }
            }
            else if (value is MarkupExtension)
            {
                // Share the actual ME directly for these 3.
                if (value is BindingBase ||
                    value is TemplateBindingExtension ||
                    value is DynamicResourceExtension)
                {
                    isValueShareable = true;
                }
                else if ((value is StaticResourceExtension) || (value is StaticResourceHolder))
                {
                    isValueShareable = false;
                }
                else
                {
                    TemplateLoadData.ServiceProviderWrapper.SetData(_sharedDpInstance, property);
                    value = (value as MarkupExtension).ProvideValue(TemplateLoadData.ServiceProviderWrapper);
                    TemplateLoadData.ServiceProviderWrapper.Clear();
 
                    if (allowRecursive)
                    {
                        // Terminate recursive checking of provided value to prevent infinite loop
                        return TrySharingValue(property, value, parentName, xamlReader, false, out sharedValue);
                    }
                    else
                    {
                        isValueShareable = true;
                    }
                }
            }
 
            if (isValueShareable)
            {
                // If we're here, that means the property can be shared
                PropertyValue propertyValue = new PropertyValue();
                propertyValue.Property = property;
                propertyValue.ChildName = parentName;
                propertyValue.ValueInternal = value;
                propertyValue.ValueType = PropertyValueType.Set;
 
                sharedValue = propertyValue;
 
                // Read the EndProperty so it's not going to be read by the outer reader
                xamlReader.Read();
                Debug.Assert(xamlReader.NodeType == System.Xaml.XamlNodeType.EndMember);
            }
 
            return isValueShareable;
        }
 
        private bool IsTypeShareable(Type type)
        {
            if ( // We handle Freezables on an per-instance basis.
                typeof(Freezable).IsAssignableFrom(type)
                ||
                // Well-known immutable CLR types
                type == typeof(string) || type == typeof(Uri) || type == 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(type)
                    &&
                    !typeof(StaticResourceExtension).IsAssignableFrom(type))
                ||
                // Styles & Templates are mostly shareable
                typeof(Style).IsAssignableFrom(type)
                ||
                typeof(FrameworkTemplate).IsAssignableFrom(type)
                ||
                // CVS might be shareable, wait for the instance check
                typeof(System.Windows.Data.CollectionViewSource).IsAssignableFrom(type)
                ||
                // Value types are immutable by nature
                (type != null && type.IsValueType))
                return true;
 
            return false;
        }
 
        private void WriteNamespaces(System.Xaml.XamlWriter writer,
                                     FrugalObjectList<System.Xaml.NamespaceDeclaration> previousNamespaces,
                                     FrugalObjectList<System.Xaml.NamespaceDeclaration> localNamespaces)
        {
            if (previousNamespaces != null)
            {
                for (int idx = 0; idx < previousNamespaces.Count; idx++)
                {
                    writer.WriteNamespace(previousNamespaces[idx]);
                }
            }
            if (localNamespaces != null)
            {
                for (int idx = 0; idx < localNamespaces.Count; idx++)
                {
                    writer.WriteNamespace(localNamespaces[idx]);
                }
            }
        }
 
 
        private static void AutoAliasContentPresenter(
            Type targetType,
            string contentSource,
            string templateChildName,
            ref FrugalStructList<ChildRecord> childRecordFromChildIndex,
            ref FrugalStructList<ItemStructMap<TriggerSourceRecord>> triggerSourceRecordFromChildIndex,
            ref FrugalStructList<ChildPropertyDependent> resourceDependents,
            ref HybridDictionary dataTriggerRecordFromBinding,
            ref bool hasInstanceValues,
            HybridDictionary childIndexFromChildName,
            bool isContentPropertyDefined,
            bool isContentSourceSet,
            bool isContentTemplatePropertyDefined,
            bool isContentTemplateSelectorPropertyDefined,
            bool isContentStringFormatPropertyDefined
            )
        {
            if (String.IsNullOrEmpty(contentSource) && isContentSourceSet == false)
                contentSource = "Content";
 
            if (!String.IsNullOrEmpty(contentSource) && !isContentPropertyDefined)
            {
                Debug.Assert(templateChildName != null);
 
                DependencyProperty dpContent = DependencyProperty.FromName(contentSource, targetType);
                DependencyProperty dpContentTemplate = DependencyProperty.FromName($"{contentSource}Template", targetType);
                DependencyProperty dpContentTemplateSelector = DependencyProperty.FromName(
                    $"{contentSource}TemplateSelector", targetType);
                DependencyProperty dpContentStringFormat = DependencyProperty.FromName($"{contentSource}StringFormat", targetType);
 
                if (dpContent == null && isContentSourceSet)
                {
                    throw new InvalidOperationException(SR.Format(SR.MissingContentSource, contentSource, targetType));
                }
 
                if (dpContent != null)
                {
                    PropertyValue pv = new PropertyValue();
                    pv.ValueType = PropertyValueType.TemplateBinding;
                    pv.ChildName = templateChildName;
                    pv.ValueInternal = new TemplateBindingExtension(dpContent);
                    pv.Property = ContentPresenter.ContentProperty;
 
                    StyleHelper.UpdateTables(ref pv, ref childRecordFromChildIndex,
                        ref triggerSourceRecordFromChildIndex,
                        ref resourceDependents,
                        ref dataTriggerRecordFromBinding,
                        childIndexFromChildName,
                        ref hasInstanceValues);
 
                }
 
                if (!isContentTemplatePropertyDefined &&
                    !isContentTemplateSelectorPropertyDefined &&
                    !isContentStringFormatPropertyDefined)
                {
                    if (dpContentTemplate != null)
                    {
                        PropertyValue pv = new PropertyValue();
                        pv.ValueType = PropertyValueType.TemplateBinding;
                        pv.ChildName = templateChildName;
                        pv.ValueInternal = new TemplateBindingExtension(dpContentTemplate);
                        pv.Property = ContentPresenter.ContentTemplateProperty;
 
                        StyleHelper.UpdateTables(ref pv, ref childRecordFromChildIndex,
                               ref triggerSourceRecordFromChildIndex,
                               ref resourceDependents,
                               ref dataTriggerRecordFromBinding,
                               childIndexFromChildName,
                               ref hasInstanceValues);
                    }
 
                    if (dpContentTemplateSelector != null)
                    {
                        PropertyValue pv = new PropertyValue();
                        pv.ValueType = PropertyValueType.TemplateBinding;
                        pv.ChildName = templateChildName;
                        pv.ValueInternal = new TemplateBindingExtension(dpContentTemplateSelector);
                        pv.Property = ContentPresenter.ContentTemplateSelectorProperty;
 
                        StyleHelper.UpdateTables(ref pv, ref childRecordFromChildIndex,
                               ref triggerSourceRecordFromChildIndex,
                               ref resourceDependents,
                               ref dataTriggerRecordFromBinding,
                               childIndexFromChildName,
                               ref hasInstanceValues);
                    }
 
                    if (dpContentStringFormat != null)
                    {
                        PropertyValue pv = new PropertyValue();
                        pv.ValueType = PropertyValueType.TemplateBinding;
                        pv.ChildName = templateChildName;
                        pv.ValueInternal = new TemplateBindingExtension(dpContentStringFormat);
                        pv.Property = ContentPresenter.ContentStringFormatProperty;
 
 
                        StyleHelper.UpdateTables(ref pv, ref childRecordFromChildIndex,
                             ref triggerSourceRecordFromChildIndex,
                             ref resourceDependents,
                             ref dataTriggerRecordFromBinding,
                             childIndexFromChildName,
                             ref hasInstanceValues);
                    }
                }
            }
        }
 
 
        private static void AutoAliasGridViewRowPresenter(
                Type targetType,
                string contentSource,
                string childName,
                ref FrugalStructList<ChildRecord> childRecordFromChildIndex,
                ref FrugalStructList<ItemStructMap<TriggerSourceRecord>> triggerSourceRecordFromChildIndex,
                ref FrugalStructList<ChildPropertyDependent> resourceDependents,
                ref HybridDictionary dataTriggerRecordFromBinding,
                ref bool hasInstanceValues,
                HybridDictionary childIndexFromChildID,
                bool isContentPropertyDefined,
                bool isColumnsPropertyDefined
                )
        {
            // <GridViewRowPresenter Content="{TemplateBinding Property=Content}" .../>
            if (!isContentPropertyDefined)
            {
                DependencyProperty dpContent = DependencyProperty.FromName("Content", targetType);
 
                if (dpContent != null)
                {
                    PropertyValue propertyValue = new PropertyValue();
                    propertyValue.ValueType = PropertyValueType.TemplateBinding;
                    propertyValue.ChildName = childName;
                    propertyValue.ValueInternal = new TemplateBindingExtension(dpContent);
                    propertyValue.Property = GridViewRowPresenter.ContentProperty;
 
                    StyleHelper.UpdateTables(ref propertyValue,
                                             ref childRecordFromChildIndex,
                                             ref triggerSourceRecordFromChildIndex,
                                             ref resourceDependents,
                                             ref dataTriggerRecordFromBinding,
                                             childIndexFromChildID,
                                             ref hasInstanceValues);
                }
            }
 
            // <GridViewRowPresenter Columns="{TemplateBinding Property=GridView.ColumnCollection}" .../>
            if (!isColumnsPropertyDefined)
            {
                PropertyValue propertyValue = new PropertyValue();
                propertyValue.ValueType = PropertyValueType.TemplateBinding;
                propertyValue.ChildName = childName;
                propertyValue.ValueInternal = new TemplateBindingExtension(GridView.ColumnCollectionProperty);
                propertyValue.Property = GridViewRowPresenter.ColumnsProperty;
 
                StyleHelper.UpdateTables(ref propertyValue,
                                         ref childRecordFromChildIndex,
                                         ref triggerSourceRecordFromChildIndex,
                                         ref resourceDependents,
                                         ref dataTriggerRecordFromBinding,
                                         childIndexFromChildID,
                                         ref hasInstanceValues);
            }
        }
 
        internal XamlType RootType { get; private set; }
 
        internal XamlType GetTypeForName(string name)
        {
            return TemplateLoadData.NamedTypes[name];
        }
 
        internal FrameworkTemplate OwnerTemplate { get; set; }
        internal IXamlObjectWriterFactory ObjectWriterFactory { get; private set; }
        internal XamlObjectWriterSettings ObjectWriterParentSettings { get; private set; }
 
        internal XamlSchemaContext SchemaContext { get; private set; }
 
        //_xamlNodeList is the postProcessed list, not the original template nodes.  TemplateContentConverter
        // and TemplateContent do that processing.
        internal XamlNodeList _xamlNodeList = null;
 
        private static SharedDp _sharedDpInstance = new SharedDp(null, null, null);
        private StackOfFrames Stack
        {
            get
            {
                return TemplateLoadData.Stack;
            }
            set
            {
                TemplateLoadData.Stack = value;
            }
        }
 
        //This will be nulled out when the FrameworkTemplate is sealed.
        internal TemplateLoadData TemplateLoadData
        {
            get;
            set;
        }
 
        internal class ServiceProviderWrapper : ITypeDescriptorContext, IXamlTypeResolver, IXamlNamespaceResolver, IProvideValueTarget
        {
            private IServiceProvider _services;
            internal StackOfFrames Frames { get; set; }
            private XamlSchemaContext _schemaContext;
            private Object _targetObject;
            private Object _targetProperty;
 
            public ServiceProviderWrapper(IServiceProvider services, XamlSchemaContext schemaContext)
            {
                _services = services;
                _schemaContext = schemaContext;
            }
            #region IServiceProvider Members
 
            object IServiceProvider.GetService(Type serviceType)
            {
                if (serviceType == typeof(IXamlTypeResolver))
                {
                    return this;
                }
                else if (serviceType == typeof(IProvideValueTarget))
                {
                    return this;
                }
                else
                {
                    return _services.GetService(serviceType);
                }
            }
 
            #endregion
 
            #region IXamlTypeResolver Members
 
            Type IXamlTypeResolver.Resolve(string qualifiedTypeName)
            {
                return _schemaContext.GetXamlType(XamlTypeName.Parse(qualifiedTypeName, this)).UnderlyingType;
            }
 
            #endregion
 
            #region IXamlNamespaceResolver Members
 
            string IXamlNamespaceResolver.GetNamespace(string prefix)
            {
                FrugalObjectList<NamespaceDeclaration> namespaces = Frames.InScopeNamespaces;
                if (namespaces != null)
                {
                    for (int idx = 0; idx < namespaces.Count; idx++)
                    {
                        if (namespaces[idx].Prefix == prefix)
                        {
                            return namespaces[idx].Namespace;
                        }
                    }
                }
 
                return ((IXamlNamespaceResolver)_services.GetService(typeof(IXamlNamespaceResolver))).GetNamespace(prefix);
            }
 
            IEnumerable<NamespaceDeclaration> IXamlNamespaceResolver.GetNamespacePrefixes()
            {
                throw new NotImplementedException();
            }
 
            #endregion
 
            #region ITypeDescriptorContext Members
 
            IContainer ITypeDescriptorContext.Container
            {
                get { return null; }
            }
 
            object ITypeDescriptorContext.Instance
            {
                get { return null; }
            }
 
            void ITypeDescriptorContext.OnComponentChanged()
            {
            }
 
            bool ITypeDescriptorContext.OnComponentChanging()
            {
                return false;
            }
 
            PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor
            {
                get { return null; }
            }
 
            #endregion
 
            public void SetData(Object targetObject, Object targetProperty)
            {
                _targetObject = targetObject;
                _targetProperty = targetProperty;
            }
            public void Clear()
            {
                _targetObject = null;
                _targetProperty = null;
            }
            Object IProvideValueTarget.TargetObject { get { return _targetObject; } }
            Object IProvideValueTarget.TargetProperty { get { return _targetProperty; } }
        }
    }
 
    //This class is meant to hold any data that a TemplateContent needs during TemplateLoad
    // that isn't needed by a FrameworkTemplate during TemplateApply.
    internal class TemplateLoadData
    {
        internal TemplateLoadData()
        {
        }
 
        internal TemplateContent.StackOfFrames Stack { get; set; }
 
        internal Dictionary<string, XamlType> _namedTypes;
        internal Dictionary<string, XamlType> NamedTypes
        {
            get
            {
                if (_namedTypes == null)
                    _namedTypes = new Dictionary<string, XamlType>();
                return _namedTypes;
            }
        }
 
        internal System.Xaml.XamlReader Reader
        {
            get;
            set;
        }
 
        internal string RootName { get; set; }
        internal object RootObject { get; set; }
        internal TemplateContent.ServiceProviderWrapper ServiceProviderWrapper { get; set; }
        internal XamlObjectWriter ObjectWriter { get; set; }
    }
}