WPF源代码分析系列一:剖析WPF模板机制的内部实现(二)

(注:本文是《剖析WPF模板机制的内部实现》系列文章的第二篇,查看上一篇文章点这里)

2. ControlTemplate

ControlTemplate类是最简单的FrameworkTemplate子类,而最常见的ControlTemplate类型变量是Control.Template属性。

上一篇我们提到,FrameworkElement子类要想生成自己的visual tree,就必须自定义一个模板给TemplateInternal属性。一个FrameworkElement子类元素的visual tree完全取决其提供给TemplateInternal属性的实际模板。

我们将看到,作为FrameworkElement的子类,Control除了覆写了TemplateInternalTemplateCache属性,还新定义了一个ControlTemplate类型的Template属性:

//*****************Control********************

        public static readonly DependencyProperty TemplateProperty =                DependencyProperty.Register(                        "Template",                        typeof(ControlTemplate),                        typeof(Control),                        new FrameworkPropertyMetadata(                                (ControlTemplate) null,  // default value                                FrameworkPropertyMetadataOptions.AffectsMeasure,                                new PropertyChangedCallback(OnTemplateChanged)));        /// <summary>        /// Template Property        /// </summary>        public ControlTemplate Template        {            get { return _templateCache; }            set { SetValue(TemplateProperty, value); }        }        // 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 = (ControlTemplate) value; }        }        // Internal helper so FrameworkElement could see call the template changed virtual        internal override void OnTemplateChangedInternal(FrameworkTemplate oldTemplate, FrameworkTemplate newTemplate)        {            OnTemplateChanged((ControlTemplate)oldTemplate, (ControlTemplate)newTemplate);        }        // Property invalidation callback invoked when TemplateProperty is invalidated        private static void OnTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)        {            Control c = (Control) d;            StyleHelper.UpdateTemplateCache(c, (FrameworkTemplate) e.OldValue, (FrameworkTemplate) e.NewValue, TemplateProperty);        }

可以看到,覆写后,TemplateInternal属性返回的就是Template,而Template属性返回的是_templateCache字段,这个字段又是TemplateCache属性的支撑字段,而TemplateCache属性只在StyleHelper.UpdateTemplateCache()方法里被修改过。这个方法的代码如下:

//*****************StyleHelper*********************    internal static void UpdateTemplateCache(      FrameworkElement fe,      FrameworkTemplate oldTemplate,      FrameworkTemplate newTemplate,      DependencyProperty templateProperty)    {        DependencyObject d = fe;// Update the template cache        fe.TemplateCache = newTemplate;         // Do template property invalidations. Note that some of the invalidations may be callouts        // that could turn around and query the template property on this node. Hence it is essential        // to update the template cache before we do this operation.        StyleHelper.DoTemplateInvalidations(fe, oldTemplate);        // Now look for triggers that might want their EnterActions or ExitActions        //  to run immediately.        StyleHelper.ExecuteOnApplyEnterExitActions(fe, null, newTemplate);    }

这意味着每次更新Control.Template都会相应更新_templateCache,从而FrameworkElement.ApplyTemplate()读到的TemplateInternal的值也就是Control.Template的值。就这样,Control类在无法覆写ApplyTemplate()方法的情况下,实现了模板应用的多态性。值得一提的是,我们后面将看到,这种模式已经成了FrameworkElement子类对虚属性TemplateInternal实现多态性的固定模式。另外,前面我们提到只有4个FrameworkElement的子类覆写了TemplateInternal属性:Control、ContentPresenter、ItemsPresenter、Page,因此可以期望在后面三种类里面也能找到类似的TemplateInternal多态性实现机制。

其他ControlTemplate类型的变量还有Page.Template,DataGrid.RowValidationErrorTemplate等。它们的模板机制与Control.Template大同小异,这里就不一一赘述了。下一篇文章我们将讨论ItemsPanelTemplate类。

(0)

相关推荐