ContentPresenter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / System / Windows / Controls / ContentPresenter.cs / 1 / ContentPresenter.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: ContentPresenter class 
// 
// Specs:       http://avalon/connecteddata/M5%20General%20Docs/Data%20Styling.mht
// 
//---------------------------------------------------------------------------

using System;
using System.Diagnostics; 
using System.ComponentModel;
 
using System.Windows.Threading; 

using System.Windows.Shapes; 
using System.Windows.Media;
using System.Windows.Data;
using System.Windows.Markup;
using MS.Internal; 
using MS.Internal.Data;
using MS.Internal.KnownBoxes; 
using System.Windows.Documents; 

using MS.Utility; 
using MS.Internal.PresentationFramework;

namespace System.Windows.Controls
{ 
    /// 
    /// 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.
    ///  
    [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();
        } 


        /// 
        ///     Default constructor 
        /// 
        ///  
        ///     Automatic determination of current Dispatcher. Use alternative constructor 
        ///     that accepts a Dispatcher for best performance.
        ///  
        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 
        //
        //----------------------------------------------------- 
 

        ///  
        ///     The DependencyProperty for the RecognizesAccessKey property.
        ///     Flags:              None
        ///     Default Value:      false
        ///  
        [CommonDependencyProperty]
        public static readonly DependencyProperty RecognizesAccessKeyProperty = 
                DependencyProperty.Register( 
                        "RecognizesAccessKey",
                        typeof(bool), 
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));

        ///  
        ///     Determine if ContentPresenter should use AccessText in its style
        ///  
        public bool RecognizesAccessKey 
        {
            get { return (bool) GetValue(RecognizesAccessKeyProperty); } 
            set { SetValue(RecognizesAccessKeyProperty, BooleanBoxes.Box(value)); }
        }

        ///  
        ///     The DependencyProperty for the Content property.
        ///     Flags:              None 
        ///     Default Value:      null 
        /// 
        // 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)));

        ///  
        ///     Content is the data used to generate the child elements of this control.
        ///  
        public object Content 
        {
            get { return GetValue(ContentControl.ContentProperty); } 
            set { SetValue(ContentControl.ContentProperty, value); }
        }

        ///  
        ///     Called when ContentProperty is invalidated on "d."
        ///  
        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 (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 
            {
                // type-based template - matches if types agree 
                Type oldType = (e.OldValue != null) ? e.OldValue.GetType() : null;
                Type newType = (e.NewValue != null) ? e.NewValue.GetType() : null;
                mismatch = (oldType != newType);
            } 

            // if the content and (old) template don't match, reselect the template 
            if (mismatch) 
            {
                ctrl._templateIsCurrent = false; 
            }

            // keep the DataContext in [....] with Content
            if (ctrl._templateIsCurrent && ctrl.Template != UIElementContentTemplate) 
            {
                ctrl.DataContext = e.NewValue; 
            } 
        }
 

        /// 
        ///     The DependencyProperty for the ContentTemplate property.
        ///     Flags:              None 
        ///     Default Value:      null
        ///  
        [CommonDependencyProperty] 
        public static readonly DependencyProperty ContentTemplateProperty =
                ContentControl.ContentTemplateProperty.AddOwner( 
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(
                                (DataTemplate)null,
                                FrameworkPropertyMetadataOptions.AffectsMeasure, 
                                new PropertyChangedCallback(OnContentTemplateChanged)));
 
        ///  
        ///     ContentTemplate is the template used to display the content of the control.
        ///  
        public DataTemplate ContentTemplate
        {
            get { return (DataTemplate) GetValue(ContentControl.ContentTemplateProperty); }
            set { SetValue(ContentControl.ContentTemplateProperty, value); } 
        }
 
        ///  
        ///     Called when ContentTemplateProperty is invalidated on "d."
        ///  
        private static void OnContentTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ContentPresenter ctrl = (ContentPresenter)d;
            ctrl._templateIsCurrent = false; 
            ctrl.OnContentTemplateChanged((DataTemplate) e.OldValue, (DataTemplate) e.NewValue);
        } 
 
        /// 
        ///     This method is invoked when the ContentTemplate property changes. 
        /// 
        /// The old value of the ContentTemplate property.
        /// The new value of the ContentTemplate property.
        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; 
        }


        ///  
        ///     The DependencyProperty for the ContentTemplateSelector property.
        ///     Flags:              None 
        ///     Default Value:      null 
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty ContentTemplateSelectorProperty =
                ContentControl.ContentTemplateSelectorProperty.AddOwner(
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata( 
                                (DataTemplateSelector)null,
                                FrameworkPropertyMetadataOptions.AffectsMeasure, 
                                new PropertyChangedCallback(OnContentTemplateSelectorChanged))); 

        ///  
        ///     ContentTemplateSelector allows the application writer to provide custom logic
        ///     for choosing the template used to display the content of the control.
        /// 
        ///  
        ///     This property is ignored if  is set.
        ///  
        public DataTemplateSelector ContentTemplateSelector 
        {
            get { return (DataTemplateSelector) GetValue(ContentControl.ContentTemplateSelectorProperty); } 
            set { SetValue(ContentControl.ContentTemplateSelectorProperty, value); }
        }

        ///  
        /// This method is used by TypeDescriptor to determine if this property should
        /// be serialized. 
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeContentTemplateSelector() 
        {
            return false;
        }
 
        /// 
        ///     Called when ContentTemplateSelectorProperty is invalidated on "d." 
        ///  
        private static void OnContentTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ContentPresenter ctrl = (ContentPresenter) d;
            ctrl._templateIsCurrent = false;
            ctrl.OnContentTemplateSelectorChanged((DataTemplateSelector) e.OldValue, (DataTemplateSelector) e.NewValue);
        } 

        ///  
        ///     This method is invoked when the ContentTemplateSelector property changes. 
        /// 
        /// The old value of the ContentTemplateSelector property. 
        /// The new value of the ContentTemplateSelector property.
        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; 
        }
 
        /// 
        ///     The DependencyProperty for the ContentStringFormat property.
        ///     Flags:              None
        ///     Default Value:      null 
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty ContentStringFormatProperty = 
                DependencyProperty.Register(
                        "ContentStringFormat", 
                        typeof(String),
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(
                                (String) null, 
                              new PropertyChangedCallback(OnContentStringFormatChanged)));
 
 
        /// 
        ///     ContentStringFormat is the format used to display the content of 
        ///     the control as a string.  This arises only when no template is
        ///     available.
        /// 
        [Bindable(true), CustomCategory("Content")] 
        public String ContentStringFormat
        { 
            get { return (String) GetValue(ContentStringFormatProperty); } 
            set { SetValue(ContentStringFormatProperty, value); }
        } 

        /// 
        ///     Called when ContentStringFormatProperty is invalidated on "d."
        ///  
        private static void OnContentStringFormatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ContentPresenter ctrl = (ContentPresenter)d; 
            ctrl.OnContentStringFormatChanged((String) e.OldValue, (String) e.NewValue);
        } 

        /// 
        ///     This method is invoked when the ContentStringFormat property changes.
        ///  
        /// The old value of the ContentStringFormat property.
        /// The new value of the ContentStringFormat property. 
        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);
        } 

        ///  
        ///     The DependencyProperty for the ContentSource property. 
        ///     Flags:              None
        ///     Default Value:      Content 
        /// 
        [CommonDependencyProperty]
        public static readonly DependencyProperty ContentSourceProperty =
                DependencyProperty.Register( 
                        "ContentSource",
                        typeof(string), 
                        typeof(ContentPresenter), 
                        new FrameworkPropertyMetadata("Content"));
 
        /// 
        ///     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". 
        /// 
        ///  
        ///     This property only makes sense in a template.  It should not be set on
        ///     an actual ContentPresenter;  there will be no effect.
        /// 
        public string ContentSource 
        {
            get { return GetValue(ContentSourceProperty) as string; } 
            set { SetValue(ContentSourceProperty, value); } 
        }
 
        //------------------------------------------------------
        //
        //  Protected Methods
        // 
        //------------------------------------------------------
 
        ///  
        /// Called when the Template's tree is about to be generated
        ///  
        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 (!_templateIsCurrent) 
            {
                EnsureTemplate(); 
                _templateIsCurrent = true;
            }
        }
 

        ///  
        /// Updates DesiredSize of the ContentPresenter.  Called by parent UIElement.  This is the first pass of layout. 
        /// 
        ///  
        /// ContentPresenter determines a desired size it needs from the child's sizing properties, margin, and requested size.
        /// 
        /// Constraint size is an "upper limit" that the return value should not exceed.
        /// The ContentPresenter's desired size. 
        protected override Size MeasureOverride(Size constraint)
        { 
            return Helper.MeasureElementWithSingleChild(this, constraint); 
        }
 

        /// 
        /// ContentPresenter computes the position of its single child inside child's Margin and calls Arrange
        /// on the child. 
        /// 
        /// Size the ContentPresenter will assume. 
        protected override Size ArrangeOverride(Size arrangeSize) 
        {
            return Helper.ArrangeElementWithSingleChild(this, arrangeSize); 
        }


        ///  
        /// Return the template to use.  This may depend on the Content, or
        /// other properties. 
        ///  
        /// 
        /// 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.
        ///  
        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 
        //
        //----------------------------------------------------- 
 
        /// 
        /// Prepare to display the item. 
        /// 
        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);
            }
        } 

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


        ///  
        /// TemplateProperty
        ///  
        internal static readonly DependencyProperty TemplateProperty = 
                DependencyProperty.Register(
                        "Template", 
                        typeof(DataTemplate),
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(
                                (DataTemplate) null,  // default value 
                                FrameworkPropertyMetadataOptions.AffectsMeasure,
                                new PropertyChangedCallback(OnTemplateChanged))); 
 

        ///  
        /// Template Property
        /// 
        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);
        }

        ///  
        ///     Template has changed
        ///  
        ///  
        ///     When a Template changes, the VisualTree is removed. The new Template's
        ///     VisualTree will be created when ApplyTemplate is called 
        /// 
        /// The old Template
        /// The new Template
        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;
        } 

        // 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; 
        }
 
        // 
        //  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(content.GetType()); 
                    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.Flags.performance, EventTrace.Level.normal); 
                if (tracingEnabled)
                { 
                    EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), MS.Utility.EventType.StartEvent, "ContentPresenter.BuildVisualTree");
                }

                ContentPresenter cp = (ContentPresenter)container; 
                Visual result = DefaultExpansion(cp.Content, cp);
 
                if (tracingEnabled) 
                {
                    EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), 
                                                         MS.Utility.EventType.EndEvent,
                                                         String.Format(System.Globalization.CultureInfo.InvariantCulture, "ContentPresenter.BuildVisualTree for CP {0}", container.GetHashCode()));
                }
 
                return (result != null);
            } 
 
            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; 
                    Type t = content.GetType(); 
                    TypeConverter tc = TypeDescriptor.GetConverter(t);
 
                    if ((stringFormat = container.ContentStringFormat) != null)
                    {
                        try
                        { 
                            stringFormat = Helper.GetEffectiveStringFormat(stringFormat);
                            textBlock.Text = String.Format(container.Language.GetSpecificCulture(), stringFormat, content); 
                            succeeded = true; 
                        }
                        catch (FormatException) 
                        {
                        }
                    }
 
                    if (!succeeded)
                    { 
                        if ((tc = TypeDescriptor.GetConverter(content.GetType())) != null && 
                                    (tc.CanConvertTo(typeof(String))))
                        { 
                            textBlock.Text = (string)tc.ConvertTo(content, typeof(string));
                        }
                        else
                        { 
                            Debug.Assert(!(tc != null && tc.CanConvertTo(typeof(UIElement))));  // this is handled by a different template
                            textBlock.Text = content.ToString(); 
                        } 
                    }
                } 
            }

        }
 
        private class DefaultSelector : DataTemplateSelector
        { 
            ///  
            /// Override this method to return an app specific .
            ///  
            /// The data content
            /// The container in which the content is to be displayed
            /// a app specific template to apply.
            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 (XmlHelper.IsXmlNode(item)) 
                        template = ((ContentPresenter)container).SelectTemplateForXML(); 
                    else if (item is Inline)
                        template = DefaultContentTemplate; 
                    else if (item != null && (tc = TypeDescriptor.GetConverter(item.GetType())) != null &&
                                tc.CanConvertTo(typeof(UIElement)))
                        template = UIElementContentTemplate;
                    else 
                        template = DefaultContentTemplate;
                } 
 
                return template;
            } 
        }

        //------------------------------------------------------
        // 
        //  Private Fields
        // 
        //----------------------------------------------------- 

        private DataTemplate _templateCache; 

        private bool _templateIsCurrent;
        private bool _contentIsItem;
 
        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 XMLFormattingTemplateField = new UncommonField();
        private static readonly UncommonField StringFormattingTemplateField = new UncommonField();
        private static readonly UncommonField AccessTextFormattingTemplateField = new UncommonField(); 
    }
} 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: ContentPresenter class 
// 
// Specs:       http://avalon/connecteddata/M5%20General%20Docs/Data%20Styling.mht
// 
//---------------------------------------------------------------------------

using System;
using System.Diagnostics; 
using System.ComponentModel;
 
using System.Windows.Threading; 

using System.Windows.Shapes; 
using System.Windows.Media;
using System.Windows.Data;
using System.Windows.Markup;
using MS.Internal; 
using MS.Internal.Data;
using MS.Internal.KnownBoxes; 
using System.Windows.Documents; 

using MS.Utility; 
using MS.Internal.PresentationFramework;

namespace System.Windows.Controls
{ 
    /// 
    /// 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.
    ///  
    [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();
        } 


        /// 
        ///     Default constructor 
        /// 
        ///  
        ///     Automatic determination of current Dispatcher. Use alternative constructor 
        ///     that accepts a Dispatcher for best performance.
        ///  
        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 
        //
        //----------------------------------------------------- 
 

        ///  
        ///     The DependencyProperty for the RecognizesAccessKey property.
        ///     Flags:              None
        ///     Default Value:      false
        ///  
        [CommonDependencyProperty]
        public static readonly DependencyProperty RecognizesAccessKeyProperty = 
                DependencyProperty.Register( 
                        "RecognizesAccessKey",
                        typeof(bool), 
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));

        ///  
        ///     Determine if ContentPresenter should use AccessText in its style
        ///  
        public bool RecognizesAccessKey 
        {
            get { return (bool) GetValue(RecognizesAccessKeyProperty); } 
            set { SetValue(RecognizesAccessKeyProperty, BooleanBoxes.Box(value)); }
        }

        ///  
        ///     The DependencyProperty for the Content property.
        ///     Flags:              None 
        ///     Default Value:      null 
        /// 
        // 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)));

        ///  
        ///     Content is the data used to generate the child elements of this control.
        ///  
        public object Content 
        {
            get { return GetValue(ContentControl.ContentProperty); } 
            set { SetValue(ContentControl.ContentProperty, value); }
        }

        ///  
        ///     Called when ContentProperty is invalidated on "d."
        ///  
        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 (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 
            {
                // type-based template - matches if types agree 
                Type oldType = (e.OldValue != null) ? e.OldValue.GetType() : null;
                Type newType = (e.NewValue != null) ? e.NewValue.GetType() : null;
                mismatch = (oldType != newType);
            } 

            // if the content and (old) template don't match, reselect the template 
            if (mismatch) 
            {
                ctrl._templateIsCurrent = false; 
            }

            // keep the DataContext in [....] with Content
            if (ctrl._templateIsCurrent && ctrl.Template != UIElementContentTemplate) 
            {
                ctrl.DataContext = e.NewValue; 
            } 
        }
 

        /// 
        ///     The DependencyProperty for the ContentTemplate property.
        ///     Flags:              None 
        ///     Default Value:      null
        ///  
        [CommonDependencyProperty] 
        public static readonly DependencyProperty ContentTemplateProperty =
                ContentControl.ContentTemplateProperty.AddOwner( 
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(
                                (DataTemplate)null,
                                FrameworkPropertyMetadataOptions.AffectsMeasure, 
                                new PropertyChangedCallback(OnContentTemplateChanged)));
 
        ///  
        ///     ContentTemplate is the template used to display the content of the control.
        ///  
        public DataTemplate ContentTemplate
        {
            get { return (DataTemplate) GetValue(ContentControl.ContentTemplateProperty); }
            set { SetValue(ContentControl.ContentTemplateProperty, value); } 
        }
 
        ///  
        ///     Called when ContentTemplateProperty is invalidated on "d."
        ///  
        private static void OnContentTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ContentPresenter ctrl = (ContentPresenter)d;
            ctrl._templateIsCurrent = false; 
            ctrl.OnContentTemplateChanged((DataTemplate) e.OldValue, (DataTemplate) e.NewValue);
        } 
 
        /// 
        ///     This method is invoked when the ContentTemplate property changes. 
        /// 
        /// The old value of the ContentTemplate property.
        /// The new value of the ContentTemplate property.
        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; 
        }


        ///  
        ///     The DependencyProperty for the ContentTemplateSelector property.
        ///     Flags:              None 
        ///     Default Value:      null 
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty ContentTemplateSelectorProperty =
                ContentControl.ContentTemplateSelectorProperty.AddOwner(
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata( 
                                (DataTemplateSelector)null,
                                FrameworkPropertyMetadataOptions.AffectsMeasure, 
                                new PropertyChangedCallback(OnContentTemplateSelectorChanged))); 

        ///  
        ///     ContentTemplateSelector allows the application writer to provide custom logic
        ///     for choosing the template used to display the content of the control.
        /// 
        ///  
        ///     This property is ignored if  is set.
        ///  
        public DataTemplateSelector ContentTemplateSelector 
        {
            get { return (DataTemplateSelector) GetValue(ContentControl.ContentTemplateSelectorProperty); } 
            set { SetValue(ContentControl.ContentTemplateSelectorProperty, value); }
        }

        ///  
        /// This method is used by TypeDescriptor to determine if this property should
        /// be serialized. 
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeContentTemplateSelector() 
        {
            return false;
        }
 
        /// 
        ///     Called when ContentTemplateSelectorProperty is invalidated on "d." 
        ///  
        private static void OnContentTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ContentPresenter ctrl = (ContentPresenter) d;
            ctrl._templateIsCurrent = false;
            ctrl.OnContentTemplateSelectorChanged((DataTemplateSelector) e.OldValue, (DataTemplateSelector) e.NewValue);
        } 

        ///  
        ///     This method is invoked when the ContentTemplateSelector property changes. 
        /// 
        /// The old value of the ContentTemplateSelector property. 
        /// The new value of the ContentTemplateSelector property.
        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; 
        }
 
        /// 
        ///     The DependencyProperty for the ContentStringFormat property.
        ///     Flags:              None
        ///     Default Value:      null 
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty ContentStringFormatProperty = 
                DependencyProperty.Register(
                        "ContentStringFormat", 
                        typeof(String),
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(
                                (String) null, 
                              new PropertyChangedCallback(OnContentStringFormatChanged)));
 
 
        /// 
        ///     ContentStringFormat is the format used to display the content of 
        ///     the control as a string.  This arises only when no template is
        ///     available.
        /// 
        [Bindable(true), CustomCategory("Content")] 
        public String ContentStringFormat
        { 
            get { return (String) GetValue(ContentStringFormatProperty); } 
            set { SetValue(ContentStringFormatProperty, value); }
        } 

        /// 
        ///     Called when ContentStringFormatProperty is invalidated on "d."
        ///  
        private static void OnContentStringFormatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ContentPresenter ctrl = (ContentPresenter)d; 
            ctrl.OnContentStringFormatChanged((String) e.OldValue, (String) e.NewValue);
        } 

        /// 
        ///     This method is invoked when the ContentStringFormat property changes.
        ///  
        /// The old value of the ContentStringFormat property.
        /// The new value of the ContentStringFormat property. 
        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);
        } 

        ///  
        ///     The DependencyProperty for the ContentSource property. 
        ///     Flags:              None
        ///     Default Value:      Content 
        /// 
        [CommonDependencyProperty]
        public static readonly DependencyProperty ContentSourceProperty =
                DependencyProperty.Register( 
                        "ContentSource",
                        typeof(string), 
                        typeof(ContentPresenter), 
                        new FrameworkPropertyMetadata("Content"));
 
        /// 
        ///     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". 
        /// 
        ///  
        ///     This property only makes sense in a template.  It should not be set on
        ///     an actual ContentPresenter;  there will be no effect.
        /// 
        public string ContentSource 
        {
            get { return GetValue(ContentSourceProperty) as string; } 
            set { SetValue(ContentSourceProperty, value); } 
        }
 
        //------------------------------------------------------
        //
        //  Protected Methods
        // 
        //------------------------------------------------------
 
        ///  
        /// Called when the Template's tree is about to be generated
        ///  
        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 (!_templateIsCurrent) 
            {
                EnsureTemplate(); 
                _templateIsCurrent = true;
            }
        }
 

        ///  
        /// Updates DesiredSize of the ContentPresenter.  Called by parent UIElement.  This is the first pass of layout. 
        /// 
        ///  
        /// ContentPresenter determines a desired size it needs from the child's sizing properties, margin, and requested size.
        /// 
        /// Constraint size is an "upper limit" that the return value should not exceed.
        /// The ContentPresenter's desired size. 
        protected override Size MeasureOverride(Size constraint)
        { 
            return Helper.MeasureElementWithSingleChild(this, constraint); 
        }
 

        /// 
        /// ContentPresenter computes the position of its single child inside child's Margin and calls Arrange
        /// on the child. 
        /// 
        /// Size the ContentPresenter will assume. 
        protected override Size ArrangeOverride(Size arrangeSize) 
        {
            return Helper.ArrangeElementWithSingleChild(this, arrangeSize); 
        }


        ///  
        /// Return the template to use.  This may depend on the Content, or
        /// other properties. 
        ///  
        /// 
        /// 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.
        ///  
        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 
        //
        //----------------------------------------------------- 
 
        /// 
        /// Prepare to display the item. 
        /// 
        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);
            }
        } 

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


        ///  
        /// TemplateProperty
        ///  
        internal static readonly DependencyProperty TemplateProperty = 
                DependencyProperty.Register(
                        "Template", 
                        typeof(DataTemplate),
                        typeof(ContentPresenter),
                        new FrameworkPropertyMetadata(
                                (DataTemplate) null,  // default value 
                                FrameworkPropertyMetadataOptions.AffectsMeasure,
                                new PropertyChangedCallback(OnTemplateChanged))); 
 

        ///  
        /// Template Property
        /// 
        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);
        }

        ///  
        ///     Template has changed
        ///  
        ///  
        ///     When a Template changes, the VisualTree is removed. The new Template's
        ///     VisualTree will be created when ApplyTemplate is called 
        /// 
        /// The old Template
        /// The new Template
        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;
        } 

        // 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; 
        }
 
        // 
        //  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(content.GetType()); 
                    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.Flags.performance, EventTrace.Level.normal); 
                if (tracingEnabled)
                { 
                    EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), MS.Utility.EventType.StartEvent, "ContentPresenter.BuildVisualTree");
                }

                ContentPresenter cp = (ContentPresenter)container; 
                Visual result = DefaultExpansion(cp.Content, cp);
 
                if (tracingEnabled) 
                {
                    EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), 
                                                         MS.Utility.EventType.EndEvent,
                                                         String.Format(System.Globalization.CultureInfo.InvariantCulture, "ContentPresenter.BuildVisualTree for CP {0}", container.GetHashCode()));
                }
 
                return (result != null);
            } 
 
            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; 
                    Type t = content.GetType(); 
                    TypeConverter tc = TypeDescriptor.GetConverter(t);
 
                    if ((stringFormat = container.ContentStringFormat) != null)
                    {
                        try
                        { 
                            stringFormat = Helper.GetEffectiveStringFormat(stringFormat);
                            textBlock.Text = String.Format(container.Language.GetSpecificCulture(), stringFormat, content); 
                            succeeded = true; 
                        }
                        catch (FormatException) 
                        {
                        }
                    }
 
                    if (!succeeded)
                    { 
                        if ((tc = TypeDescriptor.GetConverter(content.GetType())) != null && 
                                    (tc.CanConvertTo(typeof(String))))
                        { 
                            textBlock.Text = (string)tc.ConvertTo(content, typeof(string));
                        }
                        else
                        { 
                            Debug.Assert(!(tc != null && tc.CanConvertTo(typeof(UIElement))));  // this is handled by a different template
                            textBlock.Text = content.ToString(); 
                        } 
                    }
                } 
            }

        }
 
        private class DefaultSelector : DataTemplateSelector
        { 
            ///  
            /// Override this method to return an app specific .
            ///  
            /// The data content
            /// The container in which the content is to be displayed
            /// a app specific template to apply.
            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 (XmlHelper.IsXmlNode(item)) 
                        template = ((ContentPresenter)container).SelectTemplateForXML(); 
                    else if (item is Inline)
                        template = DefaultContentTemplate; 
                    else if (item != null && (tc = TypeDescriptor.GetConverter(item.GetType())) != null &&
                                tc.CanConvertTo(typeof(UIElement)))
                        template = UIElementContentTemplate;
                    else 
                        template = DefaultContentTemplate;
                } 
 
                return template;
            } 
        }

        //------------------------------------------------------
        // 
        //  Private Fields
        // 
        //----------------------------------------------------- 

        private DataTemplate _templateCache; 

        private bool _templateIsCurrent;
        private bool _contentIsItem;
 
        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 XMLFormattingTemplateField = new UncommonField();
        private static readonly UncommonField StringFormattingTemplateField = new UncommonField();
        private static readonly UncommonField AccessTextFormattingTemplateField = new UncommonField(); 
    }
} 
 

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

                        

Link Menu

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