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

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

2. ControlTemplate

我们将看到,作为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大同小异。

原文出处:博客园
原文链接: https://www.cnblogs.com/zencoder/p/14116536.html
文章标题:WPF源代码分析系列一:剖析WPF模板机制的内部实现(二)
文章链接:https://onebyone.icu/archives/1202
作者昵称:OneByOneDotNet
作者链接:https://onebyone.icu/user/1

本网站(网站地址)刊载的所有内容,包括文字、图片、音频、视频、软件、程序、以及网页版式设计等均在网上搜集。 访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。除此以外,将本网站任何内容或服务用于其他用途时,须征得本网站及相关权利人的书面许可,并支付报酬。 本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站,予以删除。 转载请注明出处

发表评论

邮箱地址不会被公开。 必填项已用*标注

WeChat
WeChat
QQ
QQ
返回顶部