原文:在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 (上)的更多相关文章

  1. 在WPF中自定义控件(3) CustomControl (下)

    原文:在WPF中自定义控件(3) CustomControl (下)   在WPF中自定义控件(3) CustomControl (下)                                 ...

  2. 在WPF中自定义控件

    一, 不一定需要自定义控件在使用WPF以前,动辄使用自定义控件几乎成了惯性思维,比如需要一个带图片的按钮,但在WPF中此类任务却不需要如此大费周章,因为控件可以嵌套使用以及可以为控件外观打造一套新的样 ...

  3. 在WPF中自定义控件(1)

    原文:在WPF中自定义控件(1)    在WPF中自定义控件(1):概述                                                   周银辉一, 不一定需要自定 ...

  4. 在WPF中自定义控件(2) UserControl

    原文:在WPF中自定义控件(2) UserControl 在WPF中自定义控件(2) UserControl                                               ...

  5. [转]在WPF中自定义控件 UserControl

    在这里我们将将打造一个UserControl(用户控件)来逐步讲解如何在WPF中自定义控件,并将WPF的一些新特性引入到自定义控件中来.我们制作了一个带语音报时功能的钟表控件, 效果如下: 在VS中右 ...

  6. WPF中的文字修饰——上划线,中划线,基线与下划线

    原文:WPF中的文字修饰——上划线,中划线,基线与下划线 我们知道,文字的修饰包括:空心字.立体字.划线字.阴影字.加粗.倾斜等.这里只说划线字的修饰方式,按划线的位置,我们可将之分为:上划线.中划线 ...

  7. WPF中在摄像头视频上叠加控件的解决方案

    一.视频呈现 前段时间,在一个wpf的项目中需要实时显示ip摄像头,对此的解决方案想必大家都应该知道很多.在winform中,我们可以将一个控件(一般用panel或者pictruebox)的句柄丢给摄 ...

  8. wpf 中自定义控件及其使用

    主要有3个步骤: 1. 首先创建一个自定义的控件,该控件继承 TextBox namespace EzIntePark.Presentation.Common { /// <summary> ...

  9. 在WPF中减少逻辑与UI元素的耦合

    原文:在WPF中减少逻辑与UI元素的耦合             在WPF中减少逻辑与UI元素的耦合 周银辉 1,    避免在逻辑中引用界面元素,别把后台数据强加给UI  一个糟糕的案例 比如说主界 ...

随机推荐

  1. mysql数据库 BETWEEN 语法的用法和边界值解析

    between用法: 用于where表达式中,选取两个值之间的数据,如: SELECT id FROM user WHERE id BETWEEN value1 AND value2; 当betwee ...

  2. 纠结的一天 —— 由base64编解码与加号、空格引起

    2014年3月14日,星期五, 23点22分 忙碌.焦头烂额.充实而又幸福的一天! 写在篇头的话: 许多时候,别人分享的经验(成功或失败),个中滋味,听者很难真正体会,直到自己遇到的那一瞬间,才会泪如 ...

  3. Waiting on Groups of Queued Tasks

    https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingG ...

  4. JQuery 禁用后退按钮

    jQuery(document).ready(function () { if (window.history && window.history.pushState) { $(win ...

  5. ECMAScript6

    ECMAScript6介绍 # ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现 # 有利于保证这门语言的开放性和中立性. # 标准在每年的 6 月份正 ...

  6. Eslint代码规范

  7. PL/SQL 数组的使用

    一.固定数组 1.在模式(schema)级创建VARRAY类型 语法: CREATE OR REPLACE TYPE varray_type_name IS VARRAY(n) OF <elem ...

  8. PL/SQL12的安装与使用

    楼主比较懒,直接放一个别人的链接吧,比较全面. 大致过程就是,下载pl/sql    下载oracle instance client    然后配置oci.dll     添加 一个连接具体数据库的 ...

  9. Object C学习笔记24-关键字总结(转)

    学习Object C也有段时间了,学习的过程中涉及到了很多Object C中的关键字,本文总结一下所涉及到的关键字以及基本语法. 1.  #import #import <> 从syste ...

  10. 动态规划(一)POJ1163

    动态规划算法是比较实用的算法之一,结合实际问题能更好的熟悉这个算法 下面以POJ1163为例子 1. 首先是题目大意 :在给定的一个数字三角形中找到一条自上而下的路径,路径每一步只能左下或者右下,最后 ...