[UWP]了解模板化控件(4):TemplatePart

原文:[UWP]了解模板化控件(4):TemplatePart

1. TemplatePart

TemplatePart(部件)是指ControlTemplate中的命名元素。控件邏輯預期這些部分存在于ControlTemplate中,并且使用protected DependencyObject GetTemplateChild(String childName)獲取它們后進行操作。

以AutoSuggestBox為例,它的ControlTemplate結構如下,可以看到AutoSuggestBox由四個TemplatePart組成,每個TemplatePart都可以在控件代碼中以編程方式訪問:

img_f47fd6786431d79d5b1c6fdc75082eb5.png

下圖顯示了AutoSuggestBox的TemplatePart:

img_20215e2baf0d5525b8ce68daa33785d4.png

2. 使用TemplatePart

上一篇文章構造了一個很基礎的控件HeaderedContentControl,這次通過擴展這個類做些試驗性質的功能來介紹模板化控件的進階知識。

新建一個名為ContentView的控件,繼承自HeaderedContentControl,它要實現的功能有兩個:

  • 控件的Header默認Opacity=0.7,當鼠標移動到控件上時,設置Header的Opacity=1。
  • 當Header為空時,隱藏用于顯示Header的HeaderContentPresenter。

雖然可以使用依賴屬性及TemplateBinding的方式實現這個需求,不過這次用TemplatePart的方式實現。很顯然,要實現這次的需求最直接的做法是獲取顯示Header的TemplatePart,然后用代碼對其進行操作。大致上分為兩步:添加TemplatePart名稱,在代碼中獲取這個部件并操作。

2.1 添加TemplatePart名稱

在ContentView的ControlTemplate中為ContentPresenter命名為HeaderContentPresenter:

<ContentPresenter x:Name="HeaderContentPresenter"
                  Foreground="{ThemeResource TextControlHeaderForeground}"
                  Margin="0,0,0,8"
                  FontWeight="Normal"
                  Content="{TemplateBinding Header}"
                  ContentTemplate="{TemplateBinding HeaderTemplate}" />

2.2 獲取TemplatePart

模板化控件在加載ControlTemplate后會調用OnApplyTemplate,可以在這個函數中調用protected DependencyObject GetTemplateChild(String childName)獲取模板中指定名字的部件。從返回值是DependencyObject可以看出,只要是DependencyObject 都能使用ControlTemplate獲取。

這段代碼演示了如何獲得顯示Header的ContentPresenter部件:

protected override void OnApplyTemplate()
{base.OnApplyTemplate();_headerPart = GetTemplateChild(HeaderPartName) as FrameworkElement;
}

注意:不要在Loaded事件中嘗試調用GetTemplateChild,因為Loaded在OnApplyTemplate前調用,而且Loaded更容易被多次觸發。

由于Template可能多次加載,或者不能正確獲取TemplatePart,所以使用TemplatePart前應該先判斷是否為空;如果要訂閱事件,應該先取消訂閱。更完整的GetTemplateChild步驟應該是:

  • 取消訂閱TemplatePart事件
  • 將TemplatePart存儲到私有字段
  • 訂閱TemplatePart事件

可以參考如下代碼:

public override void OnApplyTemplate()
{base.OnApplyTemplate();if (_button != null){_button.Click -= OnButtonClick;}_button = GetTemplateChild(PartButtonName) as ButtonBase;if (_button != null){_button.Click += OnButtonClick;}
}

2.3 完整的代碼

[TemplatePart(Name = HeaderPartName, Type = typeof(FrameworkElement))]
public sealed class ContentView : HeaderedContentControl
{public const string HeaderPartName = "HeaderContentPresenter";public ContentView(){this.DefaultStyleKey = typeof(ContentView);}private FrameworkElement _headerPart;private bool _isPointerEntered;protected override void OnApplyTemplate(){base.OnApplyTemplate();_headerPart = GetTemplateChild(HeaderPartName) as FrameworkElement;UpdateHeaderVisual();}protected override void OnPointerEntered(PointerRoutedEventArgs e){base.OnPointerEntered(e);_isPointerEntered = true;UpdateHeaderVisual();}protected override void OnPointerExited(PointerRoutedEventArgs e){base.OnPointerExited(e);_isPointerEntered = false;UpdateHeaderVisual();}protected override void OnHeaderChanged(object oldValue, object newValue){base.OnHeaderChanged(oldValue, newValue);UpdateHeaderVisual();}private void UpdateHeaderVisual(){if (_headerPart == null)return;if (_isPointerEntered)_headerPart.Opacity = 1;else_headerPart.Opacity = 0.7;if (Header == null)_headerPart.Visibility = Visibility.Collapsed;else_headerPart.Visibility = Visibility.Visible;}
}

3. x:DeferLoadStrategy="Lazy"與GetTemplateChild

標記為x:DeferLoadStrategy="Lazy"的元素將延遲加載,即不會出現在VisualTree上,直到它被調用。

假設將ContentView中HeaderContentPresenter標記為x:DeferLoadStrategy="Lazy"并且在代碼中注釋_headerPart = GetTemplateChild(HeaderPartName) as FrameworkElement這句,運行時將看不到Header的內容,并且VisualTree如下所示:

img_b419584fd7f57f5e89e9d30e5a27e2c5.png

只有代碼中執行了_headerPart = GetTemplateChild(HeaderPartName) as FrameworkElement這句后,VisualTree上才可以看到HeaderContentPresenter,如下所示:
img_61a880e1f36b36b50bc3af2ba5f25a2e.png

出于性能方面的考慮,很多UWP原生控件都會包含x:DeferLoadStrategy="Lazy"

4. TemplatePartAttribute協定

有時,為了表明控件期待在ControlTemplate存在某個特定部件,防止編輯ControlTemplate的開發人員刪除它,控件上會添加添加TemplatePartAttribute協定。上面的ContentView代碼中即包含這個協定:

[TemplatePart(Name = HeaderPartName, Type = typeof(FrameworkElement))]

這段代碼的意思是期待在ControlTemplate中存在名稱為 "HeaderContentPresenter",類型為FrameworkElement的部件。

TemplatePartAttribute在UWP中的作用好像被弱化了,不止在UWP原生控件中見不到TemplatePartAttribute,甚至在Blend中“部件”窗口也消失了。可能UWP更加建議使用VisualState。

注意:你可能會在別的地方看到部件的命名為“PART_”開頭,在WPF時代確實是這樣,到現在仍有很多人保留了這種習慣。新興的命名語法更加自然,不需要加上“PART_”開頭。不過既然Blend中沒有了“部件”窗口,用“PART_”標識部件也是個不錯的方法。

5. 原則

使用TemplatePart需要遵循以下原則:

  • 盡可能減少TemplarePartAttribute協定。
  • 在使用TemplatePart之前檢查其是否為Null。
  • 如果ControlTemplate沒有遵循TemplatePartAttribute協定也不應該拋出異常,有可能ControlTemplate的作者是故意屏蔽某項功能。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/452861.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/452861.shtml
英文地址,請注明出處:http://en.pswp.cn/news/452861.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

動態重定位的增加的緊湊功能

動態重定位增加了緊湊的功能&#xff0c;在動態的分區分配時&#xff0c;可以對外部碎片進行緊湊來為沒有內存空間進行存儲的進程進行分配。

java 重載 equals_實現Student類的equals重載函數

[java]代碼庫//測試類public class StudentDemo {public static void main(String[] args) {Student s1 new Student("000","張三",18);Student s2 new Student("000","張三",18);//隨便改boolean flag s1.equals(s2);System.out.p…

python面試題總結(2)--編碼規范

1. 什么是 PEP8? 答&#xff1a;PEP8 --《Python Enhancement Proposal #8》&#xff08;8 號 Python 增強提案&#xff09;&#xff0c;他針對的 Python 代碼格式而編訂的風格指南。 2. 了解 Python 之禪么&#xff1f; 答&#xff1a;通過 import this 語句可以獲取其具體…

【Unity熱更新】學會AssetsBundle打包、加載、卸載

本教程詳細講解什么是AssetBundle壓縮包機制!然后構建 AssetBundle、加載 AssetBundle 以及卸載 AssetBundle 的簡要教程。這一個流程就是熱更新! AssetBundles 簡介 1.什么是AssetBundles? AssetBundles是Unity中一種用于打包和存儲資源(如模型、紋理、聲音等)的文件格…

Confluence 6 訪問你的宏正文(body)

請查看 Writing User Macros 頁面獲得有關如何寫用戶宏的介紹。 這個頁面介紹你可以在用戶宏中可以使用的的代碼信息。 訪問你的宏正文&#xff08;body&#xff09; 在你用戶宏模板中的 $body 對象可以訪問訪問到傳遞到你宏正文中的內容。 當你的宏有指定的正文的時候&#xf…

hibernate主鍵生成策略

1、hibernate 要求實體類里面有一個屬性作為唯一值&#xff0c;對應的表字段是主鍵&#xff0c;主鍵可以不同的生成策略 2、hibernate 主鍵生成策略有很多的值 <generator class"native"></generator> 3、在class屬性里面有很多值 &#xff08;1&#xf…

jboss mysql cluster_jboss配置mysql數據庫連接池

jboss配置mysql數據庫連接池下面YJBYS小編為大家整理了關于jboss配置mysql數據庫連接池的文章&#xff0c;希望對你有所幫助。更多Java認證考試信息&#xff0c;盡在應屆畢業生培訓網!1&#xff1a;配置&#xff1a;JDK 1.5JBoss4.0.4Mysql5.0Myeclipse 4.12&#xff1a;建立數…

P2P-挑戰和機遇

近年來互聯網上對等連接P2P應用發展迅速&#xff0c;MP3和視頻文件共享下載的P2P流已經成為寬帶用戶流量的主體。基于P2P的即時通信和互聯網電話&#xff08;如Skype&#xff09;發展迅速&#xff0c;對等廣播P2P流媒體等正在興起。P2P協同計算和網格方興未艾。P2P 應用支持網絡…

python面試題總結(3)-- 數據類型(字符串)

1. 列舉 Python 中的基本數據類型&#xff1f; 答&#xff1a; Python3 中有六個標準的數據類型&#xff1a;數字&#xff08;Number&#xff09;、字符串&#xff08;String&#xff09;、列表&#xff08;List&#xff09;、元組&#xff08;Tuple&#xff09;、集合&#…

網頁中JS函數自動執行常用三種方法

&#xff08;1&#xff09;最簡單的調用方式&#xff0c;直接寫到html的body標簽里面&#xff1a; <body οnlοad"myFunction()"></body> <script type"text/javascript"> function myFunction(){ …

Jetty - Container源碼分析

1. 描述 Container提供管理bean的能力。 基于Jetty-9.4.8.v20171121。 1.1 API public interface Container {// 增加一個bean&#xff0c;如果bean是一個Container.Listener則隱含調用addEventListener(Container.Listener)方法// Container.Listener只關心兩個事件&#xff1…

Ubuntu中安裝FastDFS

1 安裝fastdfs依賴包 解壓縮libfastcommon-master.zip進入到libfastcommon-master的目錄中執行 ./make.sh執行 sudo ./make.sh install 2 安裝fastdfs 解壓縮fastdfs-master.zip進入到 fastdfs-master目錄中執行 ./make.sh執行 sudo ./make.sh install 3 配置跟蹤服務器tra…

python基本語句及其意思_Python語法基礎(1),一

一、Python的對象模型對象是Python語言中最基本的概率&#xff0c;在Python中處理的一切都是對象。Python中許多內置對象可提供編程者使用&#xff0c;內置對象可直接使用&#xff0c;如數字、字符串、列表 、del等&#xff1b;非內置對象需要導入模塊才能使用&#xff0c;如正…

什么是隧道技術

隧道技術是一種通過互聯網絡基礎設施在網絡之間傳遞數據的方式。使用隧道傳遞的數據可以是不同協議的數據幀或包&#xff0c;隧道協議將這些其它協議的數據幀或包重新封裝在新的包頭中發送&#xff0c;被封裝的數據包在隧道的兩個端點之間通過公共互聯網絡進行路由&#xff0c;…

詳解網絡數字電視的實現方法與關鍵技術

1、IPTV的實現方法 寬帶網絡數字電視&#xff0c;又稱IPTV或BTV&#xff0c;即交互式網絡電視&#xff0c;是一種利用寬帶互聯網、多媒體等多種技術于一體&#xff0c;向家庭用戶提供包括數字電視在內的多種交互式服務的嶄新技術。它能夠很好地適應當今網絡飛速發展的趨勢&…

有狀態的bean和無狀態的bean的區別

有狀態會話bean &#xff1a;每個用戶有自己特有的一個實例&#xff0c;在用戶的生存期內&#xff0c;bean保持了用戶的信息&#xff0c;即“有狀態”&#xff1b;一旦用戶滅亡&#xff08;調用結束或實例結束&#xff09;&#xff0c;bean的生命期也告結束。即每個用戶最初都會…

因為我想在博客園長呆,所以給博客園提一些改進建議

一晃眼我來博客園已經有4個月了&#xff0c;我的排名從9萬多上升到9千多&#xff0c;也有不少朋友關注了我&#xff0c;其實對我幫助更大的是博客園的管理團隊&#xff0c;他們對我的文章提出了很多很好的改進建議&#xff0c;從而讓我的文章水平有了很大的提升。 這里我從用戶…

double 二進制 java_C#中將double值變成二進制然后寫入文件,Java中載入該文件讀取此二進制double值時不正確...

目前已定位到是因為C#中的byte范圍是0到255&#xff0c;而java中byte值為-128到127導致的錯誤。嘗試過使用C#的sbyte來解決&#xff1a;bw1 new BinaryWriter(new FileStream("C:\\Users\\DELL\\Desktop\\SpatialIndex\\ctest1.bin", FileMode.Create));bw2 new Bi…

什么是移動IP

移動代理 &#xff08;Mobility Agent&#xff09;&#xff1a;又分為歸屬代理和外區代理兩類。歸屬代理是歸屬網上的移動代理&#xff0c;它至少有一個接口在歸屬網上。其責任是當移動節點移動到外區網時&#xff0c;截收發往該點的數據包&#xff0c;并使用隧道技術將這些數據…