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

絕刀狂花
发布: 2025-09-21 08:15:17
原创
764人浏览过

1. templatepart

TemplatePart(部件)是指ControlTemplate中的命名元素。控件逻辑预期这些部件存在于ControlTemplate中,并且通过

protected DependencyObject GetTemplateChild(String childName)
登录后复制
获取它们后进行操作。

以AutoSuggestBox为例,它的ControlTemplate结构如下,可以看到AutoSuggestBox由四个TemplatePart组成,每个TemplatePart都可以在控件代码中以编程方式访问:

[UWP 自定义控件]了解模板化控件(4):TemplatePart下图显示了AutoSuggestBox的TemplatePart:

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

2. 使用TemplatePart

上一篇文章构造了一个很基础的控件HeaderedContentControl,这次通过扩展这个类做些实验性的功能来介绍模板化控件的进阶知识。

新建一个名为ContentView的控件,继承自HeaderedContentControl,它要实现的功能有两个:

  1. 控件的Header默认Opacity=0.7,当鼠标移动到控件上时,设置Header的Opacity=1。
  2. 当Header为空时,隐藏用于显示Header的HeaderContentPresenter。

虽然可以使用依赖属性及TemplateBinding的方式实现这个需求,不过这次用TemplatePart的方式实现。很显然,要实现这次的需求最直接的做法是获取显示Header的TemplatePart,然后用代码对其进行操作。大致上分为两步:添加TemplatePart名称,在代码中获取这个部件并操作。

2.1 添加TemplatePart名称

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

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

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;
}
登录后复制

由于Template可能多次加载,或者不能正确获取TemplatePart,所以使用TemplatePart前应该先判断是否为空;如果要订阅事件,应该先取消订阅。更完整的GetTemplateChild步骤应该是:

  1. 取消订阅TemplatePart事件
  2. 将TemplatePart存储到私有字段
  3. 订阅TemplatePart事件

可以参考如下代码:

AssemblyAI
AssemblyAI

转录和理解语音的AI模型

AssemblyAI 65
查看详情 AssemblyAI
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如下所示:

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

只有代码中执行了

_headerPart = GetTemplateChild(HeaderPartName) as FrameworkElement
登录后复制
这句后,VisualTree上才可以看到HeaderContentPresenter,如下所示:

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

出于性能方面的考虑,很多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。

5. 原则

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

  1. 尽可能减少TemplatePartAttribute协定。
  2. 在使用TemplatePart之前检查其是否为Null。
  3. 如果ControlTemplate没有遵循TemplatePartAttribute协定也不应该抛出异常,有可能ControlTemplate的作者是故意屏蔽某项功能。

以上就是[UWP 自定义控件]了解模板化控件(4):TemplatePart的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号