[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.mzph.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面试题总结(3)-- 数据类型(字符串)

1. 列举 Python 中的基本数据类型&#xff1f; 答&#xff1a; Python3 中有六个标准的数据类型&#xff1a;数字&#xff08;Number&#xff09;、字符串&#xff08;String&#xff09;、列表&#xff08;List&#xff09;、元组&#xff08;Tuple&#xff09;、集合&#…

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;如正…

Ubuntu中安装nginxError

问题1&#xff1a;出现如下错误&#xff1a; ./configure: error: the HTTP rewrite module requires the PCRE library. You can either disable the module by using --without-http_rewrite_module option, or install the PCRE library into the system, or build the PCR…

esrgan_ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks【阅读笔记】

针对SRGAN提出的几点改进&#xff0c;获得了PIRM2018视觉质量的第一名。首先是使用去掉BN层的Residual in Residual Dense Block作为网络的basic unit。并且使用residual scling 和 smaller initialization帮助训练更深的网络。第二点改进是使用了Relativistic Discriminator来…

启动FastDFS服务,使用python客户端对接fastdfs完成上传测试

1.启动tracker、storage、nginx服务&#xff1a; 启动fdfs_trackerd&#xff1a;sudo service fdfs_trackerd start 启动fdfs_storaged &#xff1a;sudo service fdfs_storaged start 启动Nginx&#xff1a;sudo /usr/local/nginx/sbin/nginx 注&#xff1a;此处给出重启服务…

Python学习-终端字体高亮显示

1、采用原生转义字符序列&#xff0c;对Windows有的版本不支持&#xff08;比如win7&#xff09;&#xff0c;完美支持Linux 实现过程&#xff1a; 终端的字符颜色是用转义序列控制的&#xff0c;是文本模式下的系统显示功能&#xff0c;和具体的语言无关。 转义序列是以ESC开头…

js下载文件 java_[Java教程]使用js实现点击按钮下载文件

[Java教程]使用js实现点击按钮下载文件0 2016-11-11 19:02:54有时候我们在网页上需要增加一个下载按钮&#xff0c;让用户能够点击后下载页面上的资料&#xff0c;那么怎样才能实现功能呢&#xff1f;这里有两种方法&#xff1a;现在需要在页面上添加一个下载按钮&#xff0c;点…

Django二次开发对接FastDFS

1.自定义文件存储器类 配置文件settings中加入如下配置 # 设置Django的文件存储类、&#xff08;名字固定&#xff09; DEFAULT_FILE_STORAGEutils.fdfs.storage.FDFSStorage# 设置fdfs使用的client.conf文件路径&#xff08;名字自己定义&#xff09; FDFS_CLIENT_CONF./util…

微信支付 java 集成案例_Spring Boot项目中集成微信支付v3

1. 前言最近忙的一批&#xff0c;难得今天有喘气的机会就赶紧把最近在开发中的一些成果分享出来。前几日分享了自己写的一个微信支付V3的开发包payment-spring-boot-starter&#xff0c;就忙里偷闲完善了一波。期间给微信支付提交了6个BUG&#xff0c;跟微信支付的产品沟通了好…

16. vim

vim编辑器是vi的升级版本&#xff0c;带颜色显示安装yum install -y vim-enhanced将passwd文件复制到其他目录下&#xff0c;vim后没有颜色 一般模式上下左右方向键或kjhl四个键移动光标n方向键 向特定方向移动n位ctrl b 或 pageup 向上翻页ctrl f 或 pagedown 向下翻页0或sh…

Jmeter(三)_配置元件

HTTP Cookie Manager 用来存储浏览器产生的用户信息 Clear Cookies each Iteration&#xff1a;每次迭代请求&#xff0c;清空cookies&#xff0c;GUI中定义的任何cookie都不会被清除。Implementation&#xff1a;默认HC4CookieHandlerCookie Policy&#xff1a;将用于管理Cook…

Django项目--首页静态化

0前言 1.使用Celery生成静态页面 task.py中新增任务函数generate_static_index_html()&#xff0c;任务函数生成静态页面。 app.task def generate_static_index_html():产生首页静态页面# 获取商品的种类信息types GoodsType.objects.all()# 获取首页轮播商品信息goods_bann…

C语言指针,申请、释放内存,线程

2019独角兽企业重金招聘Python工程师标准>>> 1&#xff1a;普通情况下&#xff0c;C语言的指针是使用虚拟地址&#xff0c;并非物理地址&#xff1b; 2&#xff1a;C语言mallco函数可以根据输入的值&#xff0c;申请一块连续的内存&#xff1b;free&#xff08;*p&a…

Docker在Ubuntu16.04上安装

转自&#xff1a;http://blog.51cto.com/collen7788/2047800 1、添加Docker源 sudo apt-get update 2、增加CA证书 sudo apt-get install apt-transport-https ca-certificates 3、添加GPG Key(一种加密手段) sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:…