天天看点

[UWP]了解模板化控件(10):原则与技巧

推荐以符合以下原则的方式编写模板化控件:

选择合适的父类:选择合适的父类可以节省大量的工作,从UWP自带的控件中选择父类是最安全的做法,通常的选择是Control、ContentControl、ItemsControl,也可以选择从RangeBase、Selector中。

代码和UI分离:通常控件的开发者不能控制最终用户怎么重写ControlTemplate,尽量做到代码和UI分离可以避免更多的异常。而且先写完所有代码,再用Blend实现UI,会比在代码和UI间交错地工作更高效。

使用依赖属性:控件的使用者会认为所有控件的属性都是可以绑定的,除非有特殊理由不要破坏这个约定俗成的规则。

不要实施严格的模版约定:模版约定指TemplatePart和TemplateVisualState,应该尽可能减少约定,在没有遵循模版约定的任何一项时也不应该引发异常,要允许ControlTemplate的开发者可以通过删除某项TemplatePart或VisualState来屏蔽某项功能。

一个控件是否好用,很大一部分取决于名称。好的命名能让使用者用起来更得心应手,坏的命名只会让代码更混淆。下面总结了UWP控件命名的一般模式:

根据控件实际功能命名,譬如Button。

以父类型的名字作为后缀,如RepeatButton。

使用常用的后缀,如-Control、-Box、-Item、-View、-Viewer、-Bar。

如果控件如现有控件功能相同,可以考虑使用Extend-、Advanced-、Simple-做前缀;也可以使用公司名做前缀,譬如ComponentOne公司的C1DataGrid。

可以使用-ex做后缀,但容易和扩展方法类混淆。

ItemsControl派生类的子元素控件要使用父元素名称做前缀、-Item做后缀,譬如ComboBox的子元素ComboBoxItem。

如果控件通过鼠标选取内容(通常会打开一个Popup),可以使用-Picker做后缀。

尽量不要用-Panel做后缀,通常只有继承Panel的才会用这种方式命名,如StackPanel。但也有ControlPanel这种例外。

对于复杂的控件或控件库项目,以下技巧可能对你有帮助。

在编写模板化控件时,依赖属性最大的缺点会暴露无遗:它太复杂了。一个完整的依赖属性定义可以有20行(属性标识符、属性包装器、PropertyChangedCallback等),而且其中一部分是静态的,另外一部分不是,在类中将一个依赖属性的所有部分放在一起,还是按静态、非静态的顺序存放,这也可能引起争论。

这个系列的主旨是讲解常见的模板化控件技术,希望了解这些技术后能更轻松地构造自己的控件,对理解开源控件库的代码也有一定的帮助。

职业生涯中看过很多程序员都不会写模板化控件(毕竟大部分场景使用UserControl或修改ControlTemplate就能解决),希望这个系列可以帮到想要学习模板化控件的开发者。

虽然写得很长,其实已经尽量精简文字和内容了。平时我看到很长的文章,都会“保存到Pocket”,然后就再也没读过。汲取了这个教训,这次的文章分成多篇,尽量每篇都控制在可以三五分钟内看完。

这个系列的内容有很多来自于WPF/Silverlight的经验,虽然有一些小出入,基本上可以用在WPF的自定义控件。

如有错漏请指出。

<a href="https://docs.microsoft.com/zh-cn/windows/uwp/controls-and-patterns/control-templates">控件模板</a>

<a href="https://msdn.microsoft.com/zh-cn/library/cc278068(v=vs.95).aspx">Silverlight 控件自定义</a>

<a href="https://github.com/Microsoft/UWPCommunityToolkit">UWPCommunityToolkit</a>

继续阅读