File: System\Windows\Controls\ContentPresenter.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.
 
//
// Description: ContentPresenter class
//
// Specs:      Data Styling.mht
//
 
using System.ComponentModel;
using System.Windows.Media;
using System.Windows.Data;
using System.Windows.Markup;
using MS.Internal;
using MS.Internal.KnownBoxes;
using System.Windows.Documents;
 
using MS.Utility;
using MS.Internal.PresentationFramework;
 
namespace System.Windows.Controls
{
    /// <summary>
    /// ContentPresenter is used within the template of a content control to denote the
    /// place in the control's visual tree (control template) where the content
    /// is to be added.
    /// </summary>
    [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]
    public class ContentPresenter : FrameworkElement
    {
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------
 
        static ContentPresenter()
        {
            DataTemplate template;
            FrameworkElementFactory text;
            Binding binding;
 
            // Default template for strings when hosted in ContentPresener with RecognizesAccessKey=true
            template = new DataTemplate();
            text = CreateAccessTextFactory();
            text.SetValue(AccessText.TextProperty, new TemplateBindingExtension(ContentProperty));
            template.VisualTree = text;
            template.Seal();
            s_AccessTextTemplate = template;
 
            // Default template for strings
            template = new DataTemplate();
            text = CreateTextBlockFactory();
            text.SetValue(TextBlock.TextProperty, new TemplateBindingExtension(ContentProperty));
            template.VisualTree = text;
            template.Seal();
            s_StringTemplate = template;
 
            // Default template for XmlNodes
            template = new DataTemplate();
            text = CreateTextBlockFactory();
            binding = new Binding();
            binding.XPath = ".";
            text.SetBinding(TextBlock.TextProperty, binding);
            template.VisualTree = text;
            template.Seal();
            s_XmlNodeTemplate = template;
 
            // Default template for UIElements
            template = new UseContentTemplate();
            template.Seal();
            s_UIElementTemplate = template;
 
            // Default template for everything else
            template = new DefaultTemplate();
            template.Seal();
            s_DefaultTemplate = template;
 
            // Default template selector
            s_DefaultTemplateSelector = new DefaultSelector();
        }
 
 
        /// <summary>
        ///     Default constructor
        /// </summary>
        /// <remarks>
        ///     Automatic determination of current Dispatcher. Use alternative constructor
        ///     that accepts a Dispatcher for best performance.
        /// </remarks>
        public ContentPresenter() : base()
        {
            Initialize();
        }
 
        void Initialize()
        {
            // Initialize the _templateCache to the default value for TemplateProperty.
            // If the default value is non-null then wire it to the current instance.
            PropertyMetadata metadata = TemplateProperty.GetMetadata(DependencyObjectType);
            DataTemplate defaultValue = (DataTemplate) metadata.DefaultValue;
            if (defaultValue != null)
            {
                OnTemplateChanged(this, new DependencyPropertyChangedEventArgs(TemplateProperty, metadata, null, defaultValue));
            }
 
            DataContext = null; // this presents a uniform view:  CP always has local DC
        }
 
        //------------------------------------------------------
        //
        //  Public Properties
        //
        //------------------------------------------------------
 
 
        /// <summary>
        ///     The DependencyProperty for the RecognizesAccessKey property.
        ///     Flags:              None
        ///     Default Value:      false
        /// </summary>
        [CommonDependencyProperty]
        public static readonly DependencyProperty RecognizesAccessKeyProperty =
                DependencyProperty.Register(
                        "RecognizesAccessKey",
                        typeof(bool),
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
 
        /// <summary>
        ///     Determine if ContentPresenter should use AccessText in its style
        /// </summary>
        public bool RecognizesAccessKey
        {
            get { return (bool) GetValue(RecognizesAccessKeyProperty); }
            set { SetValue(RecognizesAccessKeyProperty, BooleanBoxes.Box(value)); }
        }
 
        /// <summary>
        ///     The DependencyProperty for the Content property.
        ///     Flags:              None
        ///     Default Value:      null
        /// </summary>
        // Any change in Content properties affectes layout measurement since
        // a new template may be used. On measurement,
        // ApplyTemplate will be invoked leading to possible application
        // of a new template.
        [CommonDependencyProperty]
        public static readonly DependencyProperty ContentProperty =
                ContentControl.ContentProperty.AddOwner(
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(
                            (object)null,
                            FrameworkPropertyMetadataOptions.AffectsMeasure,
                            new PropertyChangedCallback(OnContentChanged)));
 
        /// <summary>
        ///     Content is the data used to generate the child elements of this control.
        /// </summary>
        public object Content
        {
            get { return GetValue(ContentControl.ContentProperty); }
            set { SetValue(ContentControl.ContentProperty, value); }
        }
 
        /// <summary>
        ///     Called when ContentProperty is invalidated on "d."
        /// </summary>
        private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ContentPresenter ctrl = (ContentPresenter)d;
 
            // if we're already marked to reselect the template, there's nothing more to do
            if (!ctrl._templateIsCurrent)
                return;
 
            bool mismatch;
 
            if (e.NewValue == BindingExpressionBase.DisconnectedItem)
            {
                mismatch = false;       // do not change templates when disconnecting
            }
            else if (ctrl.ContentTemplate != null)
            {
                mismatch = false;       // explicit template - matches by fiat
            }
            else if (ctrl.ContentTemplateSelector != null)
            {
                mismatch = true;        // template selector - always re-select
            }
            else if (ctrl.Template == UIElementContentTemplate)
            {
                mismatch = true;        // direct template - always re-apply
                ctrl.Template = null;   // and release the old content so it can be re-used elsewhere
            }
            else if (ctrl.Template == DefaultContentTemplate)
            {
                mismatch = true;        // default template - always re-apply
            }
            else
            {
                // implicit template - matches if data types agree
                Type type;  // unused
                object oldDataType = DataTypeForItem(e.OldValue, ctrl, out type);
                object newDataType = DataTypeForItem(e.NewValue, ctrl, out type);
                mismatch = (oldDataType != newDataType);
 
                // but mismatch if we're displaying strings via a default template
                // and the presence of an AccessKey changes
                if (!mismatch &&
                    ctrl.RecognizesAccessKey &&
                    Object.ReferenceEquals(typeof(String), newDataType) &&
                    ctrl.IsUsingDefaultStringTemplate)
                {
                    String oldString = (String)e.OldValue;
                    String newString = (String)e.NewValue;
                    bool oldHasAccessKey = (oldString.IndexOf(AccessText.AccessKeyMarker) > -1);
                    bool newHasAccessKey = (newString.IndexOf(AccessText.AccessKeyMarker) > -1);
 
                    if (oldHasAccessKey != newHasAccessKey)
                    {
                        mismatch = true;
                    }
                }
            }
 
            // if the content and (old) template don't match, reselect the template
            if (mismatch)
            {
                ctrl._templateIsCurrent = false;
            }
 
            // keep the DataContext in sync with Content
            if (ctrl._templateIsCurrent && ctrl.Template != UIElementContentTemplate)
            {
                ctrl.DataContext = e.NewValue;
            }
        }
 
 
        /// <summary>
        ///     The DependencyProperty for the ContentTemplate property.
        ///     Flags:              None
        ///     Default Value:      null
        /// </summary>
        [CommonDependencyProperty]
        public static readonly DependencyProperty ContentTemplateProperty =
                ContentControl.ContentTemplateProperty.AddOwner(
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(
                                (DataTemplate)null,
                                FrameworkPropertyMetadataOptions.AffectsMeasure,
                                new PropertyChangedCallback(OnContentTemplateChanged)));
 
        /// <summary>
        ///     ContentTemplate is the template used to display the content of the control.
        /// </summary>
        public DataTemplate ContentTemplate
        {
            get { return (DataTemplate) GetValue(ContentControl.ContentTemplateProperty); }
            set { SetValue(ContentControl.ContentTemplateProperty, value); }
        }
 
        /// <summary>
        ///     Called when ContentTemplateProperty is invalidated on "d."
        /// </summary>
        private static void OnContentTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ContentPresenter ctrl = (ContentPresenter)d;
            ctrl._templateIsCurrent = false;
            ctrl.OnContentTemplateChanged((DataTemplate) e.OldValue, (DataTemplate) e.NewValue);
        }
 
        /// <summary>
        ///     This method is invoked when the ContentTemplate property changes.
        /// </summary>
        /// <param name="oldContentTemplate">The old value of the ContentTemplate property.</param>
        /// <param name="newContentTemplate">The new value of the ContentTemplate property.</param>
        protected virtual void OnContentTemplateChanged(DataTemplate oldContentTemplate, DataTemplate newContentTemplate)
        {
            Helper.CheckTemplateAndTemplateSelector("Content", ContentTemplateProperty, ContentTemplateSelectorProperty, this);
 
            // if ContentTemplate is really changing, remove the old template
            this.Template = null;
        }
 
 
        /// <summary>
        ///     The DependencyProperty for the ContentTemplateSelector property.
        ///     Flags:              None
        ///     Default Value:      null
        /// </summary>
        [CommonDependencyProperty]
        public static readonly DependencyProperty ContentTemplateSelectorProperty =
                ContentControl.ContentTemplateSelectorProperty.AddOwner(
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(
                                (DataTemplateSelector)null,
                                FrameworkPropertyMetadataOptions.AffectsMeasure,
                                new PropertyChangedCallback(OnContentTemplateSelectorChanged)));
 
        /// <summary>
        ///     ContentTemplateSelector allows the application writer to provide custom logic
        ///     for choosing the template used to display the content of the control.
        /// </summary>
        /// <remarks>
        ///     This property is ignored if <seealso cref="ContentTemplate"/> is set.
        /// </remarks>
        public DataTemplateSelector ContentTemplateSelector
        {
            get { return (DataTemplateSelector) GetValue(ContentControl.ContentTemplateSelectorProperty); }
            set { SetValue(ContentControl.ContentTemplateSelectorProperty, value); }
        }
 
        /// <summary>
        /// This method is used by TypeDescriptor to determine if this property should
        /// be serialized.
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeContentTemplateSelector()
        {
            return false;
        }
 
        /// <summary>
        ///     Called when ContentTemplateSelectorProperty is invalidated on "d."
        /// </summary>
        private static void OnContentTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ContentPresenter ctrl = (ContentPresenter) d;
            ctrl._templateIsCurrent = false;
            ctrl.OnContentTemplateSelectorChanged((DataTemplateSelector) e.OldValue, (DataTemplateSelector) e.NewValue);
        }
 
        /// <summary>
        ///     This method is invoked when the ContentTemplateSelector property changes.
        /// </summary>
        /// <param name="oldContentTemplateSelector">The old value of the ContentTemplateSelector property.</param>
        /// <param name="newContentTemplateSelector">The new value of the ContentTemplateSelector property.</param>
        protected virtual void OnContentTemplateSelectorChanged(DataTemplateSelector oldContentTemplateSelector, DataTemplateSelector newContentTemplateSelector)
        {
            Helper.CheckTemplateAndTemplateSelector("Content", ContentTemplateProperty, ContentTemplateSelectorProperty, this);
 
            // if ContentTemplateSelector is really changing (and in use), remove the old template
            this.Template = null;
        }
 
        /// <summary>
        ///     The DependencyProperty for the ContentStringFormat property.
        ///     Flags:              None
        ///     Default Value:      null
        /// </summary>
        [CommonDependencyProperty]
        public static readonly DependencyProperty ContentStringFormatProperty =
                DependencyProperty.Register(
                        "ContentStringFormat",
                        typeof(String),
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(
                                (String) null,
                              new PropertyChangedCallback(OnContentStringFormatChanged)));
 
 
        /// <summary>
        ///     ContentStringFormat is the format used to display the content of
        ///     the control as a string.  This arises only when no template is
        ///     available.
        /// </summary>
        [Bindable(true), CustomCategory("Content")]
        public String ContentStringFormat
        {
            get { return (String) GetValue(ContentStringFormatProperty); }
            set { SetValue(ContentStringFormatProperty, value); }
        }
 
        /// <summary>
        ///     Called when ContentStringFormatProperty is invalidated on "d."
        /// </summary>
        private static void OnContentStringFormatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ContentPresenter ctrl = (ContentPresenter)d;
            ctrl.OnContentStringFormatChanged((String) e.OldValue, (String) e.NewValue);
        }
 
        /// <summary>
        ///     This method is invoked when the ContentStringFormat property changes.
        /// </summary>
        /// <param name="oldContentStringFormat">The old value of the ContentStringFormat property.</param>
        /// <param name="newContentStringFormat">The new value of the ContentStringFormat property.</param>
        protected virtual void OnContentStringFormatChanged(String oldContentStringFormat, String newContentStringFormat)
        {
            // force on-demand regeneration of the formatting templates for XML and String content
            XMLFormattingTemplateField.ClearValue(this);
            StringFormattingTemplateField.ClearValue(this);
            AccessTextFormattingTemplateField.ClearValue(this);
        }
 
        /// <summary>
        ///     The DependencyProperty for the ContentSource property.
        ///     Flags:              None
        ///     Default Value:      Content
        /// </summary>
        [CommonDependencyProperty]
        public static readonly DependencyProperty ContentSourceProperty =
                DependencyProperty.Register(
                        "ContentSource",
                        typeof(string),
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata("Content"));
 
        /// <summary>
        ///     ContentSource is the base name to use during automatic aliasing.
        ///     When a template contains a ContentPresenter with ContentSource="Abc",
        ///     its Content, ContentTemplate, ContentTemplateSelector, and ContentStringFormat
        ///     properties are automatically aliased to Abc, AbcTemplate, AbcTemplateSelector,
        ///     and AbcStringFormat respectively.  The two most useful values for
        ///     ContentSource are "Content" and "Header";  the default is "Content".
        /// </summary>
        /// <remarks>
        ///     This property only makes sense in a template.  It should not be set on
        ///     an actual ContentPresenter;  there will be no effect.
        /// </remarks>
        public string ContentSource
        {
            get { return GetValue(ContentSourceProperty) as string; }
            set { SetValue(ContentSourceProperty, value); }
        }
 
        //------------------------------------------------------
        //
        //  Protected Methods
        //
        //------------------------------------------------------
 
        /// <summary>
        /// Called when the Template's tree is about to be generated
        /// </summary>
        internal override void OnPreApplyTemplate()
        {
            base.OnPreApplyTemplate();
 
            // If we're inflating our visual tree but our TemplatedParent is null,
            // we might have been removed from the visual tree but not have had
            // our ContentProperty invalidated.  This would mean that when we go
            // to reparent our content, we'll be looking at a stale cache.  Make
            // sure to invalidate the Content property in this case.
            if (TemplatedParent == null)
            {
                // call GetValueCore to get this value from its TemplatedParent
                InvalidateProperty(ContentProperty);
            }
 
            // If the ContentPresenter is using "default expansion", the result
            // depends on the Language property.  There is no notification when it
            // changes (i.e. no virtual OnLanguageChanged method), but it is marked
            // as AffectsMeasure, so the CP will be re-measured and will call into
            // OnPreApplyTemplate.  At this point, if Language has changed (and if
            // we're actually using it), invalidate the template.  This will cause
            // DoDefaultExpansion to run again with the new language.
            if (_language != null && _language != this.Language)
            {
                _templateIsCurrent = false;
            }
 
            if (!_templateIsCurrent)
            {
                EnsureTemplate();
                _templateIsCurrent = true;
            }
        }
 
 
        /// <summary>
        /// Updates DesiredSize of the ContentPresenter.  Called by parent UIElement.  This is the first pass of layout.
        /// </summary>
        /// <remarks>
        /// ContentPresenter determines a desired size it needs from the child's sizing properties, margin, and requested size.
        /// </remarks>
        /// <param name="constraint">Constraint size is an "upper limit" that the return value should not exceed.</param>
        /// <returns>The ContentPresenter's desired size.</returns>
        protected override Size MeasureOverride(Size constraint)
        {
            return Helper.MeasureElementWithSingleChild(this, constraint);
        }
 
 
        /// <summary>
        /// ContentPresenter computes the position of its single child inside child's Margin and calls Arrange
        /// on the child.
        /// </summary>
        /// <param name="arrangeSize">Size the ContentPresenter will assume.</param>
        protected override Size ArrangeOverride(Size arrangeSize)
        {
            return Helper.ArrangeElementWithSingleChild(this, arrangeSize);
        }
 
 
        /// <summary>
        /// Return the template to use.  This may depend on the Content, or
        /// other properties.
        /// </summary>
        /// <remarks>
        /// The base class implements the following rules:
        ///   (a) If ContentTemplate is set, use it.
        ///   (b) If ContentTemplateSelector is set, call its
        ///         SelectTemplate method.  If the result is not null, use it.
        ///   (c) Look for a DataTemplate whose DataType matches the
        ///         Content among the resources known to the ContentPresenter
        ///         (including application, theme, and system resources).
        ///         If one is found, use it.
        ///   (d) If the type of Content is "common", use a standard template.
        ///         The common types are String, XmlNode, UIElement.
        ///   (e) Otherwise, use a default template that essentially converts
        ///         Content to a string and displays it in a TextBlock.
        /// Derived classes can override these rules and implement their own.
        /// </remarks>
        protected virtual DataTemplate ChooseTemplate()
        {
            DataTemplate template = null;
            object content = Content;
 
            // ContentTemplate has first stab
            template = ContentTemplate;
 
            // no ContentTemplate set, try ContentTemplateSelector
            if (template == null)
            {
                if (ContentTemplateSelector != null)
                {
                    template = ContentTemplateSelector.SelectTemplate(content, this);
                }
            }
 
            // if that failed, try the default TemplateSelector
            if (template == null)
            {
                template = DefaultTemplateSelector.SelectTemplate(content, this);
            }
 
            return template;
        }
 
        //------------------------------------------------------
        //
        //  Internal properties
        //
        //------------------------------------------------------
 
        internal static DataTemplate AccessTextContentTemplate
        {
            get { return s_AccessTextTemplate; }
        }
 
        internal static DataTemplate StringContentTemplate
        {
            get { return s_StringTemplate; }
        }
 
        // Internal Helper so the FrameworkElement could see this property
        internal override FrameworkTemplate TemplateInternal
        {
            get { return Template; }
        }
 
        // Internal Helper so the FrameworkElement could see the template cache
        internal override FrameworkTemplate TemplateCache
        {
            get { return _templateCache; }
            set { _templateCache = (DataTemplate)value; }
        }
 
        internal bool TemplateIsCurrent
        {
            get { return _templateIsCurrent; }
        }
 
        //------------------------------------------------------
        //
        //  Internal methods
        //
        //------------------------------------------------------
 
        /// <summary>
        /// Prepare to display the item.
        /// </summary>
        internal void PrepareContentPresenter(object item,
                                DataTemplate itemTemplate,
                                DataTemplateSelector itemTemplateSelector,
                                string stringFormat)
        {
            if (item != this)
            {
                // copy templates from parent ItemsControl
                if (_contentIsItem || !HasNonDefaultValue(ContentProperty))
                {
                    Content = item;
                    _contentIsItem = true;
                }
                if (itemTemplate != null)
                    SetValue(ContentTemplateProperty, itemTemplate);
                if (itemTemplateSelector != null)
                    SetValue(ContentTemplateSelectorProperty, itemTemplateSelector);
                if (stringFormat != null)
                    SetValue(ContentStringFormatProperty, stringFormat);
            }
        }
 
        /// <summary>
        /// Undo the effect of PrepareContentPresenter.
        /// </summary>
        internal void ClearContentPresenter(object item)
        {
            if (item != this)
            {
                if (_contentIsItem)
                {
                    Content = BindingExpressionBase.DisconnectedItem;
                }
            }
        }
 
        internal static object DataTypeForItem(object item, DependencyObject target, out Type type)
        {
            if (item == null)
            {
                type = null;
                return null;
            }
 
            object dataType;
            type = ReflectionHelper.GetReflectionType(item);
 
            if (SystemXmlLinqHelper.IsXElement(item))
            {
                dataType = SystemXmlLinqHelper.GetXElementTagName(item);
                type = null;
            }
            else if (SystemXmlHelper.IsXmlNode(item))
            {
                dataType = SystemXmlHelper.GetXmlTagName(item, target);
                type = null;
            }
            else if (type == typeof(Object))
            {
                dataType = null;     // don't search for Object - perf
            }
            else
            {
                dataType = type;
            }
 
            return dataType;
        }
 
        // called when a resource change affects implicit data templates
        internal void ReevaluateTemplate()
        {
            // run the template algorithm again
            if (Template != ChooseTemplate())
            {
                // if it chooses a different template, mark the current template
                // as no longer current, and ask for re-measure
                _templateIsCurrent = false;
                InvalidateMeasure();
            }
        }
 
        //------------------------------------------------------
        //
        //  Private properties
        //
        //------------------------------------------------------
 
        static DataTemplate XmlNodeContentTemplate
        {
            get { return s_XmlNodeTemplate; }
        }
 
        static DataTemplate UIElementContentTemplate
        {
            get { return s_UIElementTemplate; }
        }
 
        static DataTemplate DefaultContentTemplate
        {
            get { return s_DefaultTemplate; }
        }
 
        static DefaultSelector DefaultTemplateSelector
        {
            get { return s_DefaultTemplateSelector; }
        }
 
        DataTemplate FormattingAccessTextContentTemplate
        {
            get
            {
                DataTemplate template = AccessTextFormattingTemplateField.GetValue(this);
                if (template == null)
                {
                    Binding binding = new Binding();
                    binding.StringFormat = ContentStringFormat;
 
                    FrameworkElementFactory text = CreateAccessTextFactory();
                    text.SetBinding(AccessText.TextProperty, binding);
 
                    template = new DataTemplate();
                    template.VisualTree = text;
                    template.Seal();
 
                    AccessTextFormattingTemplateField.SetValue(this, template);
                }
                return template;
            }
        }
 
        DataTemplate FormattingStringContentTemplate
        {
            get
            {
                DataTemplate template = StringFormattingTemplateField.GetValue(this);
                if (template == null)
                {
                    Binding binding = new Binding();
                    binding.StringFormat = ContentStringFormat;
 
                    FrameworkElementFactory text = CreateTextBlockFactory();
                    text.SetBinding(TextBlock.TextProperty, binding);
 
                    template = new DataTemplate();
                    template.VisualTree = text;
                    template.Seal();
 
                    StringFormattingTemplateField.SetValue(this, template);
                }
                return template;
            }
        }
 
        DataTemplate FormattingXmlNodeContentTemplate
        {
            get
            {
                DataTemplate template = XMLFormattingTemplateField.GetValue(this);
                if (template == null)
                {
                    Binding binding = new Binding();
                    binding.XPath = ".";
                    binding.StringFormat = ContentStringFormat;
 
                    FrameworkElementFactory text = CreateTextBlockFactory();
                    text.SetBinding(TextBlock.TextProperty, binding);
 
                    template = new DataTemplate();
                    template.VisualTree = text;
                    template.Seal();
 
                    XMLFormattingTemplateField.SetValue(this, template);
                }
                return template;
            }
        }
 
 
        /// <summary>
        /// TemplateProperty
        /// </summary>
        internal static readonly DependencyProperty TemplateProperty =
                DependencyProperty.Register(
                        "Template",
                        typeof(DataTemplate),
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(
                                (DataTemplate) null,  // default value
                                FrameworkPropertyMetadataOptions.AffectsMeasure,
                                new PropertyChangedCallback(OnTemplateChanged)));
 
 
        /// <summary>
        /// Template Property
        /// </summary>
        private DataTemplate Template
        {
            get {  return _templateCache; }
            set { SetValue(TemplateProperty, value); }
        }
 
        // Internal helper so FrameworkElement could see call the template changed virtual
        internal override void OnTemplateChangedInternal(FrameworkTemplate oldTemplate, FrameworkTemplate newTemplate)
        {
            OnTemplateChanged((DataTemplate)oldTemplate, (DataTemplate)newTemplate);
        }
 
        // Property invalidation callback invoked when TemplateProperty is invalidated
        private static void OnTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ContentPresenter c = (ContentPresenter) d;
            StyleHelper.UpdateTemplateCache(c, (FrameworkTemplate) e.OldValue, (FrameworkTemplate) e.NewValue, TemplateProperty);
        }
 
        /// <summary>
        ///     Template has changed
        /// </summary>
        /// <remarks>
        ///     When a Template changes, the VisualTree is removed. The new Template's
        ///     VisualTree will be created when ApplyTemplate is called
        /// </remarks>
        /// <param name="oldTemplate">The old Template</param>
        /// <param name="newTemplate">The new Template</param>
        protected virtual void OnTemplateChanged(DataTemplate oldTemplate, DataTemplate newTemplate)
        {
        }
 
 
        //------------------------------------------------------
        //
        //  Private methods
        //
        //------------------------------------------------------
 
        private void EnsureTemplate()
        {
            DataTemplate oldTemplate = Template;
            DataTemplate newTemplate = null;
 
            for (_templateIsCurrent = false; !_templateIsCurrent; )
            {
                // normally this loop will execute exactly once.  The only exception
                // is when setting the DataContext causes the ContentTemplate or
                // ContentTemplateSelector to change, presumably because they are
                // themselves data-bound (see bug 128119).  In that case, we need
                // to call ChooseTemplate again, to pick up the new template.
                // We detect this case because _templateIsCurrent is reset to false
                // in OnContentTemplate[Selector]Changed, causing a second iteration
                // of the loop.
                _templateIsCurrent = true;
                newTemplate = ChooseTemplate();
 
                // if the template is changing, it's important that the code that cleans
                // up the old template runs while the CP's DataContext is still set to
                // the old Content.  The way to get this effect is:
                //      a. change the template to null
                //      b. change the data context
                //      c. change the template to the new value
 
                if (oldTemplate != newTemplate)
                {
                    Template = null;
                }
 
                if (newTemplate != UIElementContentTemplate)
                {
                    // set data context to the content, so that the template can bind to
                    // properties of the content.
                    this.DataContext = Content;
                }
                else
                {
                    // If we're using the content directly, clear the data context.
                    // The content expects to inherit.
                    this.ClearValue(DataContextProperty);
                }
            }
 
            Template = newTemplate;
 
            // if the template didn't change, we still need to force the content for the template to be regenerated;
            // so call StyleHelper's DoTemplateInvalidations directly
            if (oldTemplate == newTemplate)
            {
                StyleHelper.DoTemplateInvalidations(this, oldTemplate);
            }
        }
 
        // Select a template for string content
        DataTemplate SelectTemplateForString(string s)
        {
            DataTemplate template;
            string format = ContentStringFormat;
 
            if (this.RecognizesAccessKey && s.IndexOf(AccessText.AccessKeyMarker) > -1)
            {
                template = (String.IsNullOrEmpty(format)) ? AccessTextContentTemplate : FormattingAccessTextContentTemplate;
            }
            else
            {
                template = (String.IsNullOrEmpty(format)) ? StringContentTemplate : FormattingStringContentTemplate;
            }
 
            return template;
        }
 
        // return true if the template was chosen by SelectTemplateForString
        bool IsUsingDefaultStringTemplate
        {
            get
            {
                if (Template == StringContentTemplate ||
                    Template == AccessTextContentTemplate)
                {
                    return true;
                }
 
                DataTemplate template;
 
                template = StringFormattingTemplateField.GetValue(this);
                if (template != null && template == Template)
                {
                    return true;
                }
 
                template = AccessTextFormattingTemplateField.GetValue(this);
                if (template != null && template == Template)
                {
                    return true;
                }
 
                return false;
            }
        }
 
 
        // Select a template for XML content
        DataTemplate SelectTemplateForXML()
        {
            return (String.IsNullOrEmpty(ContentStringFormat)) ? XmlNodeContentTemplate : FormattingXmlNodeContentTemplate;
        }
 
        // ContentPresenter often has occasion to display text.  The TextBlock it uses
        // should get the values for various text-related properties (foreground, fonts,
        // decoration, trimming) from the governing ContentControl.  The following
        // two methods accomplish this - first for the case where the TextBlock appears
        // in a true template, then for the case where the TextBlock is created on
        // demand via BuildVisualTree.
 
        // Create a FEF for a AccessText, to be used in a default template
        internal static FrameworkElementFactory CreateAccessTextFactory()
        {
            FrameworkElementFactory text = new FrameworkElementFactory(typeof(AccessText));
 
            return text;
        }
 
        // Create a FEF for a TextBlock, to be used in a default template
        internal static FrameworkElementFactory CreateTextBlockFactory()
        {
            FrameworkElementFactory text = new FrameworkElementFactory(typeof(TextBlock));
 
            return text;
        }
 
        // Create a TextBlock, to be used in a default "template" (via BuildVisualTree)
        static TextBlock CreateTextBlock(ContentPresenter container)
        {
            TextBlock text = new TextBlock();
 
            return text;
        }
 
        // Cache the Language property when it's used by DoDefaultExpansion, so
        // that we can detect changes.  (This could also be done by a virtual
        // OnLanguageChanged method, if FrameworkElement ever defines one.)
        private void CacheLanguage(XmlLanguage language)
        {
            _language = language;
        }
 
        //
        //  This property
        //  1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject
        //  2. This is a performance optimization
        //
        internal override int EffectiveValuesInitialSize
        {
            get { return 28; }
        }
 
        //------------------------------------------------------
        //
        //  Private nested classes
        //
        //------------------------------------------------------
 
        // Template for displaying UIElements - use the UIElement itself
        private class UseContentTemplate : DataTemplate
        {
            public UseContentTemplate()
            {
                // We need to preserve the treeState cache on a container node
                // even after all its logical children have been added. This is so the
                // construction of the template visual tree nodes can consume the cache.
                // This member helps us know whether we should retain the cache for
                // special scenarios when the visual tree is being built via BuildVisualTree
                CanBuildVisualTree = true;
            }
 
            internal override bool BuildVisualTree(FrameworkElement container)
            {
                object content = ((ContentPresenter)container).Content;
                UIElement e = content as UIElement;
                if (e == null)
                {
                    TypeConverter tc = TypeDescriptor.GetConverter(ReflectionHelper.GetReflectionType(content));
                    Debug.Assert(tc.CanConvertTo(typeof(UIElement)));
                    e = (UIElement) tc.ConvertTo(content, typeof(UIElement));
                }
 
                StyleHelper.AddCustomTemplateRoot( container, e );
 
                return true;
            }
        }
 
 
        // template for displaying content when all else fails
        private class DefaultTemplate : DataTemplate
        {
            public DefaultTemplate()
            {
                // We need to preserve the treeState cache on a container node
                // even after all its logical children have been added. This is so the
                // construction of the template visual tree nodes can consume the cache.
                // This member helps us know whether we should retain the cache for
                // special scenarios when the visual tree is being built via BuildVisualTree
                CanBuildVisualTree = true;
            }
 
            //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647
            internal override bool BuildVisualTree(FrameworkElement container)
            {
                bool tracingEnabled = EventTrace.IsEnabled(EventTrace.Keyword.KeywordGeneral, EventTrace.Level.Info);
                if (tracingEnabled)
                {
                    EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientStringBegin, EventTrace.Keyword.KeywordGeneral, EventTrace.Level.Info, "ContentPresenter.BuildVisualTree");
                }
                try
                {
                    ContentPresenter cp = (ContentPresenter)container;
                    Visual result = DefaultExpansion(cp.Content, cp);
                    return (result != null);
                }
                finally
                {
                    if (tracingEnabled)
                    {
                        EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientStringEnd, EventTrace.Keyword.KeywordGeneral, EventTrace.Level.Info, string.Create(System.Globalization.CultureInfo.InvariantCulture, $"ContentPresenter.BuildVisualTree for CP {container.GetHashCode()}"));
                    }
                }
            }
 
            private UIElement DefaultExpansion(object content, ContentPresenter container)
            {
                if (content == null)
                    return null;
 
                TextBlock textBlock = CreateTextBlock(container);
                textBlock.IsContentPresenterContainer = true; // this is done so that the TextBlock does not steal away the logical child
                if( container != null )
                {
                    StyleHelper.AddCustomTemplateRoot(
                        container,
                        textBlock,
                        false, // Do not need to check for existing visual parent since we just created it
                        true); // set treeState cache on the Text instance created
                }
 
                DoDefaultExpansion(textBlock, content, container);
 
                return textBlock;
            }
 
            private void DoDefaultExpansion(TextBlock textBlock, object content, ContentPresenter container)
            {
                Debug.Assert(!(content is String) && !(content is UIElement));  // these are handled by different templates
 
                Inline inline;
 
                if ((inline = content as Inline) != null)
                {
                    textBlock.Inlines.Add(inline);
                }
                else
                {
                    bool succeeded = false;
                    string stringFormat;
                    XmlLanguage language = container.Language;
                    System.Globalization.CultureInfo culture = language.GetSpecificCulture();
                    container.CacheLanguage(language);
 
                    if ((stringFormat = container.ContentStringFormat) != null)
                    {
                        try
                        {
                            stringFormat = Helper.GetEffectiveStringFormat(stringFormat);
                            textBlock.Text = String.Format(culture, stringFormat, content);
                            succeeded = true;
                        }
                        catch (FormatException)
                        {
                        }
                    }
 
                    if (!succeeded)
                    {
                        TypeConverter tc = TypeDescriptor.GetConverter(ReflectionHelper.GetReflectionType(content));
                        TypeContext context = new TypeContext(content);
                        if (tc != null && (tc.CanConvertTo(context, typeof(String))))
                        {
                            textBlock.Text = (string)tc.ConvertTo(context, culture, content, typeof(string));
                        }
                        else
                        {
                            Debug.Assert(!(tc != null && tc.CanConvertTo(typeof(UIElement))));  // this is handled by a different template
                            textBlock.Text = String.Format(culture, "{0}", content);
                        }
                    }
                }
            }
 
            // Some type converters need the actual object that will be converted
            // in order to answer the CanConvertTo question.  (WPF's own CommandConverter
            // is an example)   We make this object available
            // via ITypeDescriptorContext.Instance.
            private class TypeContext : ITypeDescriptorContext
            {
                object _instance;
                public TypeContext(object instance)
                {
                    _instance = instance;
                }
 
                IContainer ITypeDescriptorContext.Container { get { return null; } }
                object ITypeDescriptorContext.Instance { get { return _instance; } }
                PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor { get { return null; } }
                void ITypeDescriptorContext.OnComponentChanged() {}
                bool ITypeDescriptorContext.OnComponentChanging() { return false; }
                object IServiceProvider.GetService(Type serviceType) { return null; }
            }
        }
 
        private class DefaultSelector : DataTemplateSelector
        {
            /// <summary>
            /// Override this method to return an app specific <seealso cref="Template"/>.
            /// </summary>
            /// <param name="item">The data content</param>
            /// <param name="container">The container in which the content is to be displayed</param>
            /// <returns>a app specific template to apply.</returns>
            public override DataTemplate SelectTemplate(object item, DependencyObject container)
            {
                DataTemplate template = null;
 
                // Lookup template for typeof(Content) in resource dictionaries.
                if (item != null)
                {
                    template = (DataTemplate)FrameworkElement.FindTemplateResourceInternal(container, item, typeof(DataTemplate));
                }
 
                // default templates for well known types:
                if (template == null)
                {
                    TypeConverter tc = null;
                    string s;
 
                    if ((s = item as string) != null)
                        template = ((ContentPresenter)container).SelectTemplateForString(s);
                    else if (item is UIElement)
                        template = UIElementContentTemplate;
                    else if (SystemXmlHelper.IsXmlNode(item))
                        template = ((ContentPresenter)container).SelectTemplateForXML();
                    else if (item is Inline)
                        template = DefaultContentTemplate;
                    else if (item != null &&
                                (tc = TypeDescriptor.GetConverter(ReflectionHelper.GetReflectionType(item))) != null &&
                                tc.CanConvertTo(typeof(UIElement)))
                        template = UIElementContentTemplate;
                    else
                        template = DefaultContentTemplate;
                }
 
                return template;
            }
        }
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
 
        private DataTemplate _templateCache;
 
        private bool _templateIsCurrent;
        private bool _contentIsItem;
        private XmlLanguage _language;
 
        private static DataTemplate s_AccessTextTemplate;
        private static DataTemplate s_StringTemplate;
        private static DataTemplate s_XmlNodeTemplate;
        private static DataTemplate s_UIElementTemplate;
        private static DataTemplate s_DefaultTemplate;
        private static DefaultSelector s_DefaultTemplateSelector;
        private static readonly UncommonField<DataTemplate> XMLFormattingTemplateField = new UncommonField<DataTemplate>();
        private static readonly UncommonField<DataTemplate> StringFormattingTemplateField = new UncommonField<DataTemplate>();
        private static readonly UncommonField<DataTemplate> AccessTextFormattingTemplateField = new UncommonField<DataTemplate>();
    }
}