(注:本文是《剖析WPF模板機制的內部實作》系列文章的第二篇,查看上一篇文章點這里)
2. ControlTemplate
ControlTemplate類是最簡單的FrameworkTemplate子類,而最常見的ControlTemplate型別變數是Control.Template屬性,
上一篇我們提到,FrameworkElement子類要想生成自己的visual tree,就必須自定義一個模板給TemplateInternal屬性,一個FrameworkElement子類元素的visual tree完全取決其提供給TemplateInternal屬性的實際模板,
我們將看到,作為FrameworkElement的子類,Control除了覆寫了TemplateInternal和TemplateCache屬性,還新定義了一個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類,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/233314.html
標籤:.NET技术
