[UWP 自定义控件]了解模板化控件(5.1):TemplatePart vs. VisualState

在前两篇文章中,我们分别使用了templatepart和visualstate的方法实现了相同的功能,其中visualstate显然更具灵活性。在这种情况下,我通常更倾向于使用visualstate。然而,在实际应用中,这两种实现方式并不是互斥的,许多模板化控件会同时使用这两种方法。

使用VisualState的好处包括:

代码和UI分离,使得控件扩展更灵活。可以使用Blend轻松实现动画。

尽管VisualState有诸多优势,但并不是说所有功能都必须使用VisualState实现。以下情况我会选择使用TemplatePart:

需要快速实现一个控件。某个行为是固定的,不需要扩展。需要在代码中操作UI,例如Slider或ComboBox。为了强调某个部件是控件必需的。为了隐藏实现细节,限制派生类或ControlTemplate修改重要的逻辑。

其中,使用TemplatePart产生的扩展性问题是我谨慎使用这种方案的最大因素。

除了VisualState,TemplatePart的功能也常常会被TemplateBinding所替代。前面的例子展示了使用VisualState在UI上的优势,这次我们用另一个控件DateTimeSelector来讨论使用TemplatePart在扩展性上的其他问题。

使用TemplatePart

DateTimeSelector组合了CalendarDatePicker和TimePicker,用于选择日期和时间(SelectedDateTime)。其XAML如下:

                                                                                

相应的代码如下:

[TemplatePart(Name = DateElementPartName, Type = typeof(CalendarDatePicker))][TemplatePart(Name = TimeElementPartName, Type = typeof(TimePicker))]public class DateTimeSelector : Control{    public const string DateElementPartName = "DateElement";    public const string TimeElementPartName = "TimeElement";    public static readonly DependencyProperty SelectedDateTimeProperty =        DependencyProperty.Register("SelectedDateTime", typeof(DateTime), typeof(DateTimeSelector), new PropertyMetadata(DateTime.Now, OnSelectedDateTimeChanged));    private static void OnSelectedDateTimeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)    {        DateTimeSelector target = obj as DateTimeSelector;        DateTime oldValue = (DateTime)args.OldValue;        DateTime newValue = (DateTime)args.NewValue;        if (oldValue != newValue)            target.OnSelectedDateTimeChanged(oldValue, newValue);    }    public DateTimeSelector()    {        this.DefaultStyleKey = typeof(DateTimeSelector);    }    public DateTime SelectedDateTime    {        get { return (DateTime)GetValue(SelectedDateTimeProperty); }        set { SetValue(SelectedDateTimeProperty, value); }    }    private CalendarDatePicker _dateElement;    private TimePicker _timeElement;    private bool _isUpdatingDateTime;    protected override void OnApplyTemplate()    {        base.OnApplyTemplate();        if (_dateElement != null)            _dateElement.DateChanged -= OnDateElementDateChanged;        _dateElement = GetTemplateChild(DateElementPartName) as CalendarDatePicker;        if (_dateElement != null)            _dateElement.DateChanged += OnDateElementDateChanged;        if (_timeElement != null)            _timeElement.TimeChanged -= OnTimeElementTimeChanged;        _timeElement = GetTemplateChild(TimeElementPartName) as TimePicker;        if (_timeElement != null)            _timeElement.TimeChanged += OnTimeElementTimeChanged;        UpdateElement();    }    protected virtual void OnSelectedDateTimeChanged(DateTime oldValue, DateTime newValue)    {        UpdateElement();    }    private void OnDateElementDateChanged(CalendarDatePicker sender, CalendarDatePickerDateChangedEventArgs args)    {        UpdateSelectDateTime();    }    private void OnTimeElementTimeChanged(object sender, TimePickerValueChangedEventArgs e)    {        UpdateSelectDateTime();    }    private void UpdateElement()    {        _isUpdatingDateTime = true;        try        {            if (_dateElement != null)                _dateElement.Date = SelectedDateTime.Date;            if (_timeElement != null)                _timeElement.Time = SelectedDateTime.TimeOfDay;        }        finally        {            _isUpdatingDateTime = false;        }    }    private void UpdateSelectDateTime()    {        if (_isUpdatingDateTime)            return;        DateTime dateTime = DateTime.Now;        if (_dateElement != null && _dateElement.Date.HasValue)            dateTime = _dateElement.Date.Value.Date;        if (_timeElement != null)            dateTime = dateTime.Add(_timeElement.Time);        SelectedDateTime = dateTime;    }}

可以看出,DateTimeSelector通过监视CalendarDatePicker的DateChanged和TimePicker的TimeChanged来改变SelectedDateTime的值。

DateTimeSelector的代码非常简单,控件也运行良好,但如果某天需要将CalendarDatePicker替换为DatePicker或某个第三方的日期选择控件,DateTimeSelector就无能为力了,既不能通过修改ControlTemplate,也不能通过继承来达到目的。

使用TemplateBinding

通常在构建这类控件时,应先考虑其数据和行为,而不关心其UI。DateTimeSelector最核心的功能是通过选择Date和Time得出组合起来的DateTime,那么就可以先写出如下的类:

public class DateTimeSelector2 : Control{    public static readonly DependencyProperty DateProperty =        DependencyProperty.Register("Date", typeof(DateTime), typeof(DateTimeSelector2), new PropertyMetadata(DateTime.Now, OnDateChanged));    private static void OnDateChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)    {        DateTimeSelector2 target = obj as DateTimeSelector2;        DateTime oldValue = (DateTime)args.OldValue;        DateTime newValue = (DateTime)args.NewValue;        if (oldValue != newValue)            target.OnDateChanged(oldValue, newValue);    }    public static readonly DependencyProperty TimeProperty =        DependencyProperty.Register("Time", typeof(TimeSpan), typeof(DateTimeSelector2), new PropertyMetadata(TimeSpan.Zero, OnTimeChanged));    private static void OnTimeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)    {        DateTimeSelector2 target = obj as DateTimeSelector2;        TimeSpan oldValue = (TimeSpan)args.OldValue;        TimeSpan newValue = (TimeSpan)args.NewValue;        if (oldValue != newValue)            target.OnTimeChanged(oldValue, newValue);    }    public static readonly DependencyProperty DateTimeProperty =        DependencyProperty.Register("DateTime", typeof(DateTime), typeof(DateTimeSelector2), new PropertyMetadata(DateTime.Now, OnDateTimeChanged));    private static void OnDateTimeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)    {        DateTimeSelector2 target = obj as DateTimeSelector2;        DateTime oldValue = (DateTime)args.OldValue;        DateTime newValue = (DateTime)args.NewValue;        if (oldValue != newValue)            target.OnDateTimeChanged(oldValue, newValue);    }    public DateTimeSelector2()    {        this.DefaultStyleKey = typeof(DateTimeSelector2);    }    public DateTime Date    {        get { return (DateTime)GetValue(DateProperty); }        set { SetValue(DateProperty, value); }    }    public TimeSpan Time    {        get { return (TimeSpan)GetValue(TimeProperty); }        set { SetValue(TimeProperty, value); }    }    public DateTime DateTime    {        get { return (DateTime)GetValue(DateTimeProperty); }        set { SetValue(DateTimeProperty, value); }    }    private bool _isUpdatingDateTime;    protected virtual void OnDateChanged(DateTime oldValue, DateTime newValue)    {        UpdateDateTime();    }    protected virtual void OnTimeChanged(TimeSpan oldValue, TimeSpan newValue)    {        UpdateDateTime();    }    protected virtual void OnDateTimeChanged(DateTime oldValue, DateTime newValue)    {        _isUpdatingDateTime = true;        try        {            Date = newValue.Date;            Time = newValue.TimeOfDay;        }        finally        {            _isUpdatingDateTime = false;        }    }    private void UpdateDateTime()    {        if (_isUpdatingDateTime)            return;        DateTime = Date.Date.Add(Time);    }}

控件的代码并不清楚ControlTemplate中包含什么控件,它只关心自己的数据。

在XAML中通过绑定使用这些数据。

                                                                                                                                                                

[UWP 自定义控件]了解模板化控件(5.1):TemplatePart vs. VisualState

这里给出了两个Style,分别使用了CalendarDatePicker和DatePicker,通过TwoWay Binding访问DateTimeSelector2中的Date属性。如果你的TemplatedControl需要有良好的扩展能力,可以尝试使用这种方式。

以上就是[UWP 自定义控件]了解模板化控件(5.1):TemplatePart vs. VisualState的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/191949.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
mysql如何递归查询所有数据
上一篇 2026年9月7日 15:25:48
PHP框架的扩展机制:趋势和未来展望
下一篇 2025年12月12日 02:14:44

相关推荐

  • Win7电脑待机怎么设置?

    当今社会,很多人在空闲时间都喜欢使用电脑娱乐或工作,但有时会遇到突发情况需要暂时离开,这时除了直接关机之外,还有其他方式可以让电脑处于一种低功耗状态,同时还能快速恢复操作。不过,不少朋友并不清楚如何开启电脑的待机功能,接下来就跟随小编一起来看看具体的操作步骤吧! 近日,一位用户向我们发来求助信息,表…

    2026年9月7日
    000
  • windows10怎么更改用户账户(C盘Users)文件夹名_windows10用户文件夹重命名教程

    必须通过管理员账户和注册表修改来安全重命名C盘Users下的用户文件夹。首先启用Administrator账户并登录;接着在管理员环境下重命名目标用户文件夹;然后进入注册表编辑器,找到对应ProfileImagePath项,将其路径更新为新名称;推荐创建从原路径指向新路径的软链接以确保兼容性;最后注…

    2026年9月7日
    000
  • Win10自带的杀毒软件在哪里?Win10自带杀毒软件的位置

    Win10自带的杀毒软件在哪里?Win10自带杀毒软件的位置Win10自带的杀毒软件在哪里?Win10自带杀毒软件的位置Win10自带的杀毒软件在哪里?Win10自带杀毒软件的位置Win10自带的杀毒软件在哪里?Win10自带杀毒软件的位置

    在windows 10操作系统里,系统自带了一款防护工具,可以帮助我们保障网络环境下的设备安全。那么,这个内置的安全软件到底位于哪里呢?接下来就跟随小编的脚步一起来探索一下吧! Windows 10内置防护软件的位置 首先,请查看电脑屏幕右下角的任务栏区域,那里可能会隐藏着我们的防护软件图标。 点击…

    2026年9月7日 用户投稿
    900
  • Win10缺少DLL文件怎么解决 5种常见解决方案

    Win10缺少DLL文件怎么解决 5种常见解决方案Win10缺少DLL文件怎么解决 5种常见解决方案Win10缺少DLL文件怎么解决 5种常见解决方案Win10缺少DLL文件怎么解决 5种常见解决方案

    当你在使用windows 10系统安装程序或运行某些软件时,可能会碰到“缺少dll文件”的提示,导致程序无法正常启动或运行。为了解决这类问题,本文将为你提供几种常见的应对方法,帮助你快速修复windows 10中dll文件缺失的故障。 一、重启计算机 当出现DLL文件缺失的错误时,建议先尝试最基础的…

    2026年9月7日 用户投稿
    000
  • 百度地图怎么预定酒店_百度地图酒店预定操作方法

    百度地图提供三种酒店预订方式:一、搜索“酒店”后在地图上点击图标查看详情并预订;二、通过底部“酒店”入口浏览列表并下单;三、导航时使用“沿途搜索”查找并预订目的地附近的酒店。 如果您想在出行时快速找到并预订合适的住宿,百度地图的酒店预订功能可以提供从搜索、比价到直接下单的一站式服务。以下是完成酒店预…

    2026年9月7日
    000
  • 电脑硬盘容量怎么看?这几招一看就懂

    电脑硬盘容量怎么看?这几招一看就懂电脑硬盘容量怎么看?这几招一看就懂电脑硬盘容量怎么看?这几招一看就懂电脑硬盘容量怎么看?这几招一看就懂

    电脑硬盘作为存储操作系统和各类文件的核心组件,掌握其容量信息对合理分配存储资源至关重要。如果你不清楚如何查看电脑硬盘的容量,本文将为你提供几种实用且操作简便的方法,助你迅速获取所需信息。 一、通过“此电脑”查看硬盘分区容量 最直接的方式是利用Windows系统自带的“此电脑”功能,适用于所有使用Wi…

    2026年9月7日 用户投稿
    000
  • 如何在Win10电脑中创建移动热点?请看图文说明

    如何在Win10电脑中创建移动热点?请看图文说明如何在Win10电脑中创建移动热点?请看图文说明如何在Win10电脑中创建移动热点?请看图文说明如何在Win10电脑中创建移动热点?请看图文说明

    手机没有流量、周围又没有无线网,想要上网冲浪,我们可以在已经联网的电脑中创建热点并进行共享。本文就以windows10为例,详细介绍使用电脑开启热点的操作方法,请参考。 如何在笔记本电脑中开启热点? 打开笔记本电脑,确保网络连接正常,呼出开始菜单,点击【设置】,进入Windows设置窗口,选择【网络…

    2026年9月7日 用户投稿
    100
  • 新硬盘第一次使用需要怎样做 新手必看的操作指南

    新硬盘第一次使用需要怎样做 新手必看的操作指南新硬盘第一次使用需要怎样做 新手必看的操作指南新硬盘第一次使用需要怎样做 新手必看的操作指南新硬盘第一次使用需要怎样做 新手必看的操作指南

    不少用户在安装完新硬盘后,发现电脑系统中并未显示新添加的硬盘。此时不必慌张,这并不代表硬盘存在问题。实际上,新硬盘在首次使用前需要经过初始化、分区和格式化等步骤,系统才能识别并正常使用。本文将为你详细介绍新硬盘接入电脑后必须完成的设置流程,确保它顺利投入使用。 一、确认硬盘是否正确安装并被系统识别 …

    2026年9月7日 用户投稿
    000
  • Flash导入音乐失败?解决方法

    Flash导入音乐失败?解决方法Flash导入音乐失败?解决方法Flash导入音乐失败?解决方法Flash导入音乐失败?解决方法

    制作flash动画或mv时,常会遇到下载的mp3音频无法导入的情况。这通常是由于文件编码方式或格式不被flash支持所致。通过将音频进行格式转换、调整编码参数,或使用专业音频处理工具重新导出,便可解决兼容性问题,顺利将音乐嵌入flash项目中。 1、 尝试将名为“小苹果.mp3”的音频文件导入Fla…

    2026年9月7日 用户投稿
    000
  • Win10系统玩LOL游戏打不开提示句柄无效怎么办?

    win10系统玩lol游戏无法启动并显示句柄无效怎么办?不少玩家喜欢在电脑上玩lol(英雄联盟),但在尝试打开游戏时,却遇到了无法启动的情况,同时还收到句柄无效的提示。如果你也遇到了这样的问题,本文将为你提供解决方案。 具体步骤: 处理方法: 如果提示是因为安装了第三方软件导致的,请尝试卸载这些软件…

    2026年9月7日
    000
  • AMD 更新 24H2 后 CPU 游戏性能大提升!

    AMD 更新 24H2 后 CPU 游戏性能大提升!AMD 更新 24H2 后 CPU 游戏性能大提升!AMD 更新 24H2 后 CPU 游戏性能大提升!AMD 更新 24H2 后 CPU 游戏性能大提升!

    自从windows 11问世以来,其游戏表现一直受到广泛质疑,尤其是对于amd用户而言。因此,许多amd用户依然选择留在windows 10系统上。然而,随着windows 11 24h2的推出,这一状况或将发生改变。微软在这次更新中修复了amd的分支预测问题,使得amd处理器在24h2版本上的游戏…

    2026年9月7日 用户投稿
    000
  • VSCode语言怎么输入数据_VSCode调试时交互式数据输入教程

    答案:配置launch.json的console为integratedTerminal可实现调试时交互输入,中文乱码需确保UTF-8编码和正确locale,自动输入推荐从文件读取,多文件调试可通过compounds配置多进程。 VSCode调试时交互式数据输入,其实就是让你的程序在调试过程中能像正常…

    2026年9月7日
    100
  • Win7下给系统创建密码重设盘的方法

    教你如何在windows 7系统中制作密码恢复盘。 方法步骤 首先,准备好一个U盘,并将其插入电脑。随后打开控制面板,找到并点击“用户账户”选项,然后从左侧菜单中选择“制作密码恢复盘”。 点击“制作密码恢复盘”后,系统会启动“密码恢复盘”配置向导。点击“下一步”按钮,此时会在驱动器中生成一个密码密钥…

    2026年9月7日
    000
  • Win11任务栏卡死重启也没有用怎么办?解决Win11任务栏卡死问题

    Win11任务栏卡死重启也没有用怎么办?解决Win11任务栏卡死问题Win11任务栏卡死重启也没有用怎么办?解决Win11任务栏卡死问题Win11任务栏卡死重启也没有用怎么办?解决Win11任务栏卡死问题Win11任务栏卡死重启也没有用怎么办?解决Win11任务栏卡死问题

    最近,许多用户已经安装了windows 11操作系统,但近期不少用户反馈,在9月3日更新后,他们的电脑任务栏出现了卡顿现象,即便尝试重启windows资源管理器或重启电脑也无法解决问题。今天,小编将为大家介绍几种解决这一问题的方法。 方法一: 按下Ctrl+Shift+Esc组合键,打开任务管理器。…

    2026年9月7日 用户投稿
    100
  • 解决Faceit OAuth授权码交换访问令牌时遇到的401错误

    本文旨在帮助开发者解决在使用Faceit OAuth进行授权码交换访问令牌时遇到的401错误。通过分析错误原因,并提供正确的URL编码Base64凭据的解决方案,确保成功获取访问令牌,从而顺利调用Faceit API。 在使用Faceit OAuth进行授权码交换访问令牌时,开发者可能会遇到401错…

    2026年9月7日
    000
  • Win11一定要gpt格式吗 Win11分区详细介绍

    我们在安装操作系统时都会面临分区的选择问题,最近有用户在安装windows 11系统时收到提示,要求使用gpt分区格式。那么,windows 11是否一定需要gpt格式呢?其实并非如此,即使采用uefi分区方式,同样可以安装windows 11。接下来就让我们详细了解这一情况。 Windows 11…

    2026年9月7日
    000
  • 罐头日记反馈提交指南

    罐头日记怎么提交意见反馈?详细操作步骤来了! 1、 打开罐头日记App,点击右上角的头像图标进入个人中心。 2、 进入“我的”页面后,找到并点击“意见反馈”选项。 3、 跳转至反馈界面,输入你想提出的建议或问题,完成后点击“发送”即可成功提交。 以上就是罐头日记反馈提交指南的详细内容,更多请关注创想…

    2026年9月7日
    000
  • win10无法设置默认保存位置怎么办?win10无法设置默认保存位置解决方法

    大家好,我是你们的电脑小助手,今天要和大家分享的是Win10 1909版本中遇到无法自定义默认保存路径的问题该如何处理。相信不少朋友都碰到过类似情况,明明希望文件保存到自己设定的目录,系统却总是固执地存到原定位置。别着急,接下来我将为大家介绍几种实用的解决办法。 首先我们需要了解,在Win10 19…

    2026年9月7日
    100
  • Win10启用来宾帐户的操作方法

    Win10启用来宾帐户的操作方法Win10启用来宾帐户的操作方法Win10启用来宾帐户的操作方法Win10启用来宾帐户的操作方法

    在windows 10系统中,来宾帐户是一种权限相对较低的用户帐户类型,主要用于外来用户访问本地共享文件时使用。接下来将详细介绍如何开启来宾帐户的具体步骤。 1、首先打开控制面板,然后选择并点击“用户帐户”选项。 2、在进入用户帐户界面后,找到并点击“管理其他帐户”。 3、接着点击界面上的“Gues…

    2026年9月7日 用户投稿
    100
  • win10安全模式跳过开机密码的解决办法

    win10安全模式跳过开机密码的解决办法win10安全模式跳过开机密码的解决办法win10安全模式跳过开机密码的解决办法win10安全模式跳过开机密码的解决办法

    为了验证win10安全模式能否绕过开机密码这一设想是否可行,今天特意花了一些时间进行了实际测试,并将详细的步骤和结果整理成了图文教程,这就是今天要分享的内容——win10安全模式下是否能够成功跳过开机密码以解决密码登录的问题。 1、首先,我们打开 Windows 设置,通过按下 Win+I 键来访问…

    2026年9月7日 用户投稿
    200

发表回复

登录后才能评论
关注微信