在WPF中自定义控件(3) CustomControl (上)
原文:在WPF中自定义控件(3) CustomControl (上)
在WPF中自定义控件(3) CustomControl (上)
周银辉
为快速地为你的应用定制一个零部件,你需要的是UserControl,这可以参考在WPF中自定义控件(2) UserControl, 为了让你打造的控件更标准化,更灵活以及更具有普遍意义,你需要用到的CustomControl,这正是本文要介绍的.
1,新建CustomControl
在选择控件基类后,第一件事情便是在你的项目中新建"CustomControl",我们会发现在项目中自动生成了一个*.CS(或*.VB或其他)文件以及\Themes\Generic.xaml(如果原来没有的话),他们分别是CustomControl的后台代码文件(Code Behind)与控件的默认主题文件,打开\Themes\Generic.xaml,你会发现其中自动生成了一个Style,这是你的控件的默认样式,正如WPF内置控件也有它的默认样式一样.这时,我们的工作就被分成了两个部分,一是在XXX.cs文件中编辑控件逻辑,而是在Generic.xaml中编写其UI.
2,Generic.xaml中的Style是如何与我们的控件联系在一起的
打开XXX.cs文件,你会发现静态构造方法中,VS自动地帮你覆盖了控件的DefaultStyleKey值:
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}我们知道DefaultStyleKeyProperty是FrameworkElement以及FrameworkContentElement类用来指示控件的默认样式键值的属性,该属性有一个很特别的地方就是我们不能够用继承的思想来思考它,比如说Button的默认样式键值是Style1,其子类MyButton的默认样式键值是Style2(或者没有指定默认样式),尽管MyButton可以向上转型成Button类,但我们并不希望其转型后的默认样式键值为Style1.所以WPF采用了在子类控件的静态构造方法中重写DefaultStyleKey元数据的方式来指定该子类控件的默认样式.上面代码中,我们将new FrameworkPropertyMetadata(typeof(CustomControl1))指定为其新的元数据值,这个值代表着,我们将在资源字典中查找一个键值为typeof(CustomControl1)的Style来做为控件的默认样式.而这个样式刚好被我们定义在了Generic.xaml中:
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
这是大家可能有个疑问,上面XAML中的Style并没有指定Key值啊,而我们的控件要求的默认样式Key值为typeof(CustomControl1), 并且资源字典中的元素肯定是要有Key的? 这是Style的基本知识了,在WPF中,为Style指定Key时有两种方式:一是明确指定Key,而是在没有明确指定Key的情况下指定TargetType,WPF会自动地将其可Key设置为typeof(TargetType).如果你有在Blend中为控件打造Style的经验的话,你会注意到新建一个Style时,Blend会提供一个"Apply to ALL"选项,这也是为什么你打造的Style可以"Apply to all"的奥秘所在.
3, "Generic.xaml"这个名称并非偶然
通过上面的叙述,你可能会有冲动将Generic.xaml中的Style代码剪切出来,粘贴到任何一个我们的控件可以找到的地方,然后把Generic.xaml删掉或改成更优雅的名称,如果你运气好的话,这是可行的,因为控件会自下而上(Page,App,Theme)去查找其所需要的Style,但此时你已经犯了一个潜在的错误:你没有为控件提供默认的样式.这里的默认样式其实是说"在默认主题中或没有为该控件找到当前操作系统对应的主题时采用的的样式".这涉及到WPF中Theme的相关话题了,有兴趣可以参考msdn相关SDK.
4,打造你的控件逻辑
这是必然的,添加属性,添加事件,方法等等,这些你可以参考在WPF中自定义控件(2) UserControl ,这里就不重复叙述了.
5,打造控件UI
这里值得一提的是我非常佩服在VS的XAML海洋里"裸泳"的兄弟们,不过我更推荐使用Microsoft Expression Blend来完成这项艰巨的任务.另外,如果你发现WPF内置控件在Blend中很好用而我们自己打造的控件却不是这样,那么请注意了,你的控件逻辑可能设计得不规范.
6,控件UI部分与逻辑部分的耦合度.
这是一个容易被忽略但却非常重要的问题, 我们之所以使用CustomControl而不是UserControl,是因为我们希望自己的控件能向WPF内置控件一样,其UI能轻易地被其他用户定制或我们将来所改变.也就是说其视觉树不能与后台逻辑纠缠在一起,因为其视觉树中的元素完全可能被你的控件用户改变.比如,如果你的控件的视觉树中有一个Button,而你在该Button的Click事件中做了一些控件的逻辑处理,那么很可能你的控件打造失败了,因为该Button可能会在用户重新定义控件Template时被删除.
关于如何将这种耦合降到最低,敬请关注"在WPF中自定义控件(3) CustomControl (下)"
在WPF中自定义控件(3) CustomControl (上)的更多相关文章
- 在WPF中自定义控件(3) CustomControl (下)
原文:在WPF中自定义控件(3) CustomControl (下) 在WPF中自定义控件(3) CustomControl (下) ...
- 在WPF中自定义控件
一, 不一定需要自定义控件在使用WPF以前,动辄使用自定义控件几乎成了惯性思维,比如需要一个带图片的按钮,但在WPF中此类任务却不需要如此大费周章,因为控件可以嵌套使用以及可以为控件外观打造一套新的样 ...
- 在WPF中自定义控件(1)
原文:在WPF中自定义控件(1) 在WPF中自定义控件(1):概述 周银辉一, 不一定需要自定 ...
- 在WPF中自定义控件(2) UserControl
原文:在WPF中自定义控件(2) UserControl 在WPF中自定义控件(2) UserControl ...
- [转]在WPF中自定义控件 UserControl
在这里我们将将打造一个UserControl(用户控件)来逐步讲解如何在WPF中自定义控件,并将WPF的一些新特性引入到自定义控件中来.我们制作了一个带语音报时功能的钟表控件, 效果如下: 在VS中右 ...
- WPF中的文字修饰——上划线,中划线,基线与下划线
原文:WPF中的文字修饰——上划线,中划线,基线与下划线 我们知道,文字的修饰包括:空心字.立体字.划线字.阴影字.加粗.倾斜等.这里只说划线字的修饰方式,按划线的位置,我们可将之分为:上划线.中划线 ...
- WPF中在摄像头视频上叠加控件的解决方案
一.视频呈现 前段时间,在一个wpf的项目中需要实时显示ip摄像头,对此的解决方案想必大家都应该知道很多.在winform中,我们可以将一个控件(一般用panel或者pictruebox)的句柄丢给摄 ...
- wpf 中自定义控件及其使用
主要有3个步骤: 1. 首先创建一个自定义的控件,该控件继承 TextBox namespace EzIntePark.Presentation.Common { /// <summary> ...
- 在WPF中减少逻辑与UI元素的耦合
原文:在WPF中减少逻辑与UI元素的耦合 在WPF中减少逻辑与UI元素的耦合 周银辉 1, 避免在逻辑中引用界面元素,别把后台数据强加给UI 一个糟糕的案例 比如说主界 ...
随机推荐
- 中间件事务码R3AC1里Block Size的含义
在中间件事务码R3AC1可以为一个中间件的适配器对象维护Block size的大小. 以上图的尺寸为50为例,假设在ERP系统里有110个设备(equipment)需要下载,那么CRM中间件会自动生成 ...
- PythonTip(1)
发现一个Python的题库,嘿嘿,练练手吧~~~ http://www.pythontip.com/ a + b 描述: 给你两个数a.b,请你计算它们的和,并输出. 例如: a = 3, b = 2 ...
- POJ 3321 DFS序
Apple Tree Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 30636 Accepted: 9162 Descr ...
- 【[HEOI2016/TJOI2016]游戏】
据说是网络流棋盘模型了 我们把每一个连续子段都看成一个点,我们先把所有的行上的连续子段找出来给他们编上号,所有列上的连续子段找出来也编上号 现在每个格子都有两个编号了,\(a[i][j]\)表示行所对 ...
- win10的host设置
路径:C:\Windows\System32\drivers\etc\hosts 例如: 127.0.0.1 localhost 10.201.3.177 apmdbm1
- caffe实现focal loss层的一些理解和对实现一个layer层易犯错的地方的总结
首先要在caffe.proto中的LayerParameter中增加一行optional FocalLossParameter focal_loss_param = 205;,然后再单独在caffe. ...
- css实现单行的靠左靠右和居中效果
1.父元素 text-align:center 2.子元素 .left{ float:left; } .right{ float:right; } .center{ display:inline ...
- json sort
Array.sort()方法是用来对数组项进行排序的 ,默认情况下是进行升序排列.sort() 方法可以接受一个 方法为参数. sort()排序时每次比较两个数组项都回执行这个参数,并把两个比较的数组 ...
- markdown的常用高级操作。
符号 说明 对应编码(使用时去掉空格) 英文怎么说 & AND 符号 & amp; ampersand < 小于 & lt; little 大于 & gt; gr ...
- MvcApplication 中方法的那点事
最近比较闲,不知道干点啥,想找兼职没有合适的,不找工资又不够花,o(︶︿︶)o 唉! 说多了都是泪,入正题吧. 首先,新建一个MVC4.0项目,建好之后打开Global.asax文件,在MVCAppl ...