[UWP]了解模板化控件(5.2):UserControl vs. TemplatedControl
1. UserControl vs. TemplatedControl
在UWP中自定义控件常常会遇到这个问题:使用UserControl还是TemplatedControl来自定义控件。
1.1 使用UserControl自定义控件
- 继承自UserControl。
- 由复数控件组合而成。
- 包含XAML及CodeBehind。
- 优点:
- 上手简单。
- 可以在CodeBehind直接访问UI元素。
- 开发速度很快。
- 缺点:
- 不能使用ControlTemplate进行定制。
- 通常很难继承及扩展。
- 使用场景:
- 需要快速实现一个只有简单功能的控件,而且无需扩展性。
- 不需要可以改变UI。
- 不需要在不同项目中共享控件。
- 使用UserControl的控件:
- Page及DropShadowPanel都是UserControl。
1.2 使用CustomControl自定义控件
- 继承自Control或其派生类。
- 代码和XAML分离,可以没有XAML。
- 可以使用ControlTemplate。
- 控件库中的控件通常都是CustomControl。
- 优点:
- 更加灵活,容易扩展。
- UI和代码分离。
- 缺点:
- 较高的上手难度。
- 使用场景:
- 需要一个可以扩展功能的灵活的控件。
- 需要定制UI。
- 需要在不同的项目中使用。
- 使用CustomControl的控件:
- 控件库中提供的元素,除了直接继承自FrameworkElement的Panel、Shape、TextBlock等少数元素,其它大部分都是CustomControl。
2. 实践:使用UserControl实现DateTimeSelector
上一篇的DateTimeSelector例子很适合讨这个问题。这个控件没有复杂的逻辑,用UserControl的方式实现很简单,代码如下:
public sealed partial class DateTimeSelector3 : UserControl
{
/// <summary>
/// 标识 DateTime 依赖属性。
/// </summary>
public static readonly DependencyProperty DateTimeProperty =
DependencyProperty.Register("DateTime", typeof(DateTime?), typeof(DateTimeSelector3), new PropertyMetadata(null, OnDateTimeChanged));
private static void OnDateTimeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
DateTimeSelector3 target = obj as DateTimeSelector3;
DateTime? oldValue = (DateTime?)args.OldValue;
DateTime? newValue = (DateTime?)args.NewValue;
if (oldValue != newValue)
target.OnDateTimeChanged(oldValue, newValue);
}
public DateTimeSelector3()
{
this.InitializeComponent();
DateTime = System.DateTime.Now;
TimeElement.TimeChanged += OnTimeChanged;
DateElement.DateChanged += OnDateChanged;
}
/// <summary>
/// 获取或设置DateTime的值
/// </summary>
public DateTime? DateTime
{
get { return (DateTime?)GetValue(DateTimeProperty); }
set { SetValue(DateTimeProperty, value); }
}
private bool _isUpdatingDateTime;
private void OnDateTimeChanged(DateTime? oldValue, DateTime? newValue)
{
_isUpdatingDateTime = true;
try
{
if (DateElement != null && DateTime != null)
DateElement.Date = DateTime.Value;
if (TimeElement != null && DateTime != null)
TimeElement.Time = DateTime.Value.TimeOfDay;
}
finally
{
_isUpdatingDateTime = false;
}
}
private void OnDateChanged(object sender, DatePickerValueChangedEventArgs e)
{
UpdateDateTime();
}
private void OnTimeChanged(object sender, TimePickerValueChangedEventArgs e)
{
UpdateDateTime();
}
private void UpdateDateTime()
{
if (_isUpdatingDateTime)
return;
DateTime = DateElement.Date.Date.Add(TimeElement.Time);
}
}
XAML:
<StackPanel>
<DatePicker x:Name="DateElement" />
<TimePicker x:Name="TimeElement"
Margin="0,5,0,0" />
</StackPanel>
代码真的很简单,不需要GetTemplateChild,不需要DefaultStyleKey,不需要Blend,熟练的话大概5分钟就能写好一个。
使用UserControl有这些好处:
- 快速。
- 可以直接查看设计视图,不需要用Blend。
- 可以直接访问XAML中的元素。
当然坏处也不少:
- 不可以通过ControlTemplate修改UI。
- 难以继承并修改。
- UI和代码高度耦合。
如果控件只是内部使用,不是放在类库中向第三者公开,也没有修改的必要,使用UserControl也是合适的,毕竟它符合80/20原则:使用20%的时间完成了80%的功能。
3. 混合方案
如果需要快速实现控件,又需要适当的扩展能力,可以实现一个继承UserControl的基类,再通过UserControl的方式派生这个基类。
public class DateTimeSelectorBase : UserControl
创建一个名为DateTimeSelectorBase的类,继承自UserControl,其它代码基本上照抄上一篇文章中的DatetimeSelector2,只不过删除了构造函数中的代码,因为不需要DefaultStyle。
然后用普通的方式新建一个UserControl,在XAML和CodeBehind中将基类改成DateTimeSelectorBase,如下所示:
<local:DateTimeSelectorBase x:Class="TemplatedControlSample.DateTimeSelector4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TemplatedControlSample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Name="DateTimeSelector"
d:DesignHeight="300"
d:DesignWidth="400">
<local:DateTimeSelectorBase.Resources>
<local:DateTimeOffsetConverter x:Key="DateTimeOffsetConverter" />
<local:TimeSpanConverter x:Key="TimeSpanConverter" />
</local:DateTimeSelectorBase.Resources>
<StackPanel>
<DatePicker Margin="0,0,0,5"
Date="{Binding Date,ElementName=DateTimeSelector,Mode=TwoWay,Converter={StaticResource DateTimeOffsetConverter}}" />
<TimePicker Time="{Binding Time,ElementName=DateTimeSelector,Mode=TwoWay}" />
</StackPanel>
</local:DateTimeSelectorBase>
public sealed partial class DateTimeSelector4 : DateTimeSelectorBase
{
public DateTimeSelector4()
{
this.InitializeComponent();
}
}
这样既可以在不同的派生类使用不同的UI,也可以使用设计视图,结合了UserControl和TemplatedControl的优点。缺点是不可以使用ControlTemplate,而且不清楚这个控件的开发者会直观地以为这是TemplatedControl,使用上会造成一些混乱。
[UWP]了解模板化控件(5.2):UserControl vs. TemplatedControl的更多相关文章
- [UWP 自定义控件]了解模板化控件(5.2):UserControl vs. TemplatedControl
1. UserControl vs. TemplatedControl 在UWP中自定义控件常常会遇到这个问题:使用UserControl还是TemplatedControl来自定义控件. 1.1 使 ...
- [UWP]了解模板化控件(1):基础知识
1.概述 UWP允许开发者通过两种方式创建自定义的控件:UserControl和TemplatedControl(模板化控件).这个主题主要讲述如何创建和理解模板化控件,目标是能理解模板化控件常见的知 ...
- [UWP]了解模板化控件(2):模仿ContentControl
ContentControl是最简单的TemplatedControl,而且它在UWP出场频率很高.ContentControl和Panel是VisualTree的基础,可以说几乎所有VisualTr ...
- [UWP]了解模板化控件(8):ItemsControl
1. 模仿ItemsControl 顾名思义,ItemsControl是展示一组数据的控件,它是UWP UI系统中最重要的控件之一,和展示单一数据的ContentControl构成了UWP UI的绝大 ...
- [UWP]了解模板化控件(10):原则与技巧
1. 原则 推荐以符合以下原则的方式编写模板化控件: 选择合适的父类:选择合适的父类可以节省大量的工作,从UWP自带的控件中选择父类是最安全的做法,通常的选择是Control.ContentContr ...
- [UWP]了解模板化控件(4):TemplatePart
1. TemplatePart TemplatePart(部件)是指ControlTemplate中的命名元素.控件逻辑预期这些部分存在于ControlTemplate中,并且使用protected ...
- [UWP]了解模板化控件(9):UI指南
1. 使用TemplateSettings统一外观 TemplateSettings提供一组只读属性,用于在新建ControlTemplate时使用这些约定的属性. 譬如,修改HeaderedCont ...
- [UWP]了解模板化控件(5.1):TemplatePart vs. VisualState
1. TemplatePart vs. VisualState 在前面两篇文章中分别使用了TemplatePart及VisualState的方式实现了相同的功能,其中明显VisualState的方式更 ...
- UserControl VS TemplatedControl
一:首先来看一下UserControl 熟悉XAML的朋友们都知道,当我们创建一个用户控件的时候,VS会自动为我们生成一个XXX.xaml文件和XXX..xaml.cs文件,XAML文件用于进行控件的 ...
随机推荐
- Postgresql_fqw
Postgresql_fqw 测试环境 Ubuntu 16.04 LTS云主机2台,主机名为pg1(192.168.0.34)和pg2(192.168.0.39). 安装postgresql 下面这个 ...
- PostMessage,模拟键盘输入
for i := 0 to length(tel) do begin //SendMessage(cHwnd,WM_KEYDOWN,Integer(tel[ ...
- 从 RequireJs 源码剖析脚本加载原理
引言 俗话说的好,不喜欢研究原理的程序员不是好的程序员,不喜欢读源码的程序员不是好的 jser.这两天看到了有关前端模块化的问题,才发现 JavaScript 社区为了前端工程化真是煞费苦心.今天研究 ...
- visual studio高效率插件及快捷键
visual studio从2010开始支持插件安装(工具->扩展管理器),这里推荐几个插件,可以极大的提升开发效率: Visual Assist X(VAssistX) VAssistX是wh ...
- 《javascript 高级程序设计》笔记
1-4章 1.变量①.ECMAScript 变量是松散类型的,也就是说可以用来保存任何类型的数据.换句话说每个变量仅仅是一个用于保存值的占位符.②.如果在函数中使用var定义一个变量,那么这个变量在函 ...
- 是什么优化让 .NET Core 性能飙升?
.NET Core(开放源代码,跨平台,x-copy可部署等)有许多令人兴奋的方面,其中最值得称赞的就是其性能了. 感谢所有社区开发人员对.NET Core做出的贡献,其中的许多改进也将在接下来的几个 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- Python面向对象编程(四)
1.多态 多态的概念虽然现在才说,但是我们一直在用.多态就是多种形态的意思,动物都猫,狗,猪等等,这些都是动物的多种形态. 反映在Python中,多态就意味着就算不知道变量所引用的对象类型是什么,也能 ...
- Python学习之数据类型
整数 Python可以处理任意大小的整数,在程序中的表示方法和数学上的写法一模一样,例如:1,100,-8080,0,等等. 用十六进制表示整数比较方便,十六进制用0x前缀和0-9,a-f表示,例如: ...
- SpringMVC源码情操陶冶-FreeMarker之web配置
前言:本文不讲解FreeMarkerView视图的相关配置,其配置基本由FreeMarkerViewResolver实现,具体可参考>>>SpringMVC源码情操陶冶-ViewRe ...