[UWP]了解模板化控件(5.2):UserControl vs. TemplatedControl
2018-01-25 23:35
555 查看
原文:[UWP]了解模板化控件(5.2):UserControl vs. TemplatedControl
由复数控件组合而成。
包含XAML及CodeBehind。
优点:
上手简单。
可以在CodeBehind直接访问UI元素。
开发速度很快。
缺点:
不能使用ControlTemplate进行定制。
通常很难继承及扩展。
使用场景:
需要快速实现一个只有简单功能的控件,而且无需扩展性。
不需要可以改变UI。
不需要在不同项目中共享控件。
使用UserControl的控件:
Page及DropShadowPanel都是UserControl。
代码和XAML分离,可以没有XAML。
可以使用ControlTemplate。
控件库中的控件通常都是CustomControl。
优点:
更加灵活,容易扩展。
UI和代码分离。
缺点:
较高的上手难度。
使用场景:
需要一个可以扩展功能的灵活的控件。
需要定制UI。
需要在不同的项目中使用。
使用CustomControl的控件:
控件库中提供的元素,除了直接继承自FrameworkElement的Panel、Shape、TextBlock等少数元素,其它大部分都是CustomControl。
XAML:
代码真的很简单,不需要GetTemplateChild,不需要DefaultStyleKey,不需要Blend,熟练的话大概5分钟就能写好一个。
使用UserControl有这些好处:
快速。
可以直接查看设计视图,不需要用Blend。
可以直接访问XAML中的元素。
当然坏处也不少:
不可以通过ControlTemplate修改UI。
难以继承并修改。
UI和代码高度耦合。
如果控件只是内部使用,不是放在类库中向第三者公开,也没有修改的必要,使用UserControl也是合适的,毕竟它符合80/20原则:使用20%的时间完成了80%的功能。
创建一个名为DateTimeSelectorBase的类,继承自UserControl,其它代码基本上照抄上一篇文章中的DatetimeSelector2,只不过删除了构造函数中的代码,因为不需要DefaultStyle。
然后用普通的方式新建一个UserControl,在XAML和CodeBehind中将基类改成DateTimeSelectorBase,如下所示:
这样既可以在不同的派生类使用不同的UI,也可以使用设计视图,结合了UserControl和TemplatedControl的优点。缺点是不可以使用ControlTemplate,而且不清楚这个控件的开发者会直观地以为这是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
- [UWP]了解模板化控件(5.1):TemplatePart vs. VisualState
- UserControl VS TemplatedControl
- [UWP]了解模板化控件(2):模仿ContentControl
- [UWP]了解模板化控件(5.1):TemplatePart vs. VisualState
- [UWP]了解模板化控件(5.1):TemplatePart vs. VisualState
- [UWP]了解模板化控件(10):原则与技巧
- Windows 10(UWP)开发技巧 - PageUserControl
- [UWP]了解模板化控件(5):VisualState
- [UWP]了解模板化控件(9):UI指南
- [UWP]了解模板化控件(8):ItemsControl
- [UWP 自定义控件]了解模板化控件(2):模仿ContentControl
- [WPF] UserControl vs CustomControl
- [UWP]了解模板化控件(6):使用附加属性
- [UWP]了解模板化控件(7):支持Command
- [WPF] UserControl vs CustomControl
- [UWP]了解模板化控件(8):ItemsControl
- [UWP]了解模板化控件(7):支持Command
- [UWP]了解模板化控件(9):UI指南