zoukankan      html  css  js  c++  java
  • [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,使用上会造成一些混乱。

  • 相关阅读:
    ImagView
    Menu(二)在代码中add
    Menu菜单键(一)
    不区分大小写
    ASP.NET中的一些小技巧
    常用的CSS标签标记属性翻译注释
    页面自动刷新和自动跳转代码
    ASP.NET中利用存储过程实现模糊查询
    打开页面时光标自动在输入框
    一些页面自动跳转的实现
  • 原文地址:https://www.cnblogs.com/dino623/p/UserControlvsTemplatedControl.html
Copyright © 2011-2022 走看看