在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 一个糟糕的案例 比如说主界 ...
随机推荐
- Zabbix监控 windows agent安装配置
下载Windows的zabbix客户端 载地址:http://www.zabbix.com/download.php 选择windows版本的agent下载 从官方下载Zabbix Agent后,压缩 ...
- NO.001-2018.02.06《木兰花·拟古决绝词柬友》清代:纳兰性德
木兰花·拟古决绝词柬友原文.翻译及赏析_纳兰性德_古诗文网 木兰花·拟古决绝词柬友 清代:纳兰性德 人生若只如初见,何事秋风悲画扇.与意中人相处应当总像刚刚相识的时候,是那样地甜蜜,那样地温馨,那 ...
- Codeforces Round #375 (Div. 2) D. Lakes in Berland (DFS或并查集)
D. Lakes in Berland time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- react中使用react-transition-group实现动画
css动画的方式,比较局限,涉及到一些js动画的时候没法处理了.react-transition-group是react的第三方模块,借住这个模块可以更方便的实现更加复杂的动画效果 https://g ...
- POJ 3764 The xor-longest Path 【01字典树&&求路径最大异或和&&YY】
题目传送门:http://poj.org/problem?id=3764 The xor-longest Path Time Limit: 2000MS Memory Limit: 65536K ...
- 如何在vue2.0项目中引用element-ui和echart.js
1 项目中怎样添加elment-ui 和 echart.js 1.1直接在packjson 里面的 dependencies 配置 "element-ui": "^1.3 ...
- 八数码(IDA*算法)
八数码 IDA*就是迭代加深和A*估价的结合 在迭代加深的过程中,用估计函数剪枝优化 并以比较优秀的顺序进行扩展,保证最早搜到最优解 需要空间比较小,有时跑得比A*还要快 #include<io ...
- 【题解】POJ1845 Sumdiv(乘法逆元+约数和)
POJ1845:http://poj.org/problem?id=1845 思路: AB可以表示成多个质数的幂相乘的形式:AB=(a1n1)*(a2n2)* ...*(amnm) 根据算数基本定理可 ...
- Ueditor上传图片到本地改造到上传图片到七牛云存储
作为新手说多了都是泪啊!我特别想记录一下作为菜鸟时的坑.看看以后是否会看着笑出来. 为什么要改到云存储上就不说了.好处多多. 视频教程上使用的又拍云同时也提到了七牛云.下来我自己也查了下.又拍云是试用 ...
- [Linux]文件浏览
1.使用file命令查看文件中数据的类型 [oracle@linuxforlijiaman Desktop]$ ls linux oracle.txt test.png [oracle@linuxfo ...