《Programming WPF》翻译 第5章 7.控件模板
原文:《Programming WPF》翻译 第5章 7.控件模板
如果仔细的看我们当前的TTT游戏,会发现Button对象并没有完全为我们工作。哪些TTT面板有内圆角?
图5-14

这里,我们真正需要的是能够保持按钮的行为,如支持内容和点击事件,但是我们想要接管这些按钮的外观。WPF允许这种方式,因为内在的控件创建的时候是缺少外观性的,例如,他们提供行为,但是外观可以被完全包装在客户端控件的外面。
还记得我们是如何使用数据模板,来为非可视化对象提供外观的么?我们能够使用控件模板对控件做同样的事情,这将是一组StoryBoard,触发器,以及大多数重要的提供控件外观的元素。
为了修复我们的按钮外观,我们创建了一个控件模板的资源。让我们从示例5-31出发,这是一个带有简单的矩形,和以后考虑如何显示实际的按钮内容。
示例5-31
<Window.Resources>
<ControlTemplate x:Key="ButtonTemplate">
<Rectangle />
</ControlTemplate>

<!-- let's just try one button for now
-->
<Button Template="{StaticResource ButtonTemplate}"
/>

</Window.Resources>图5-15显示了设置一个单独按钮的Template属性的结果。
注意到按钮过去样子的痕迹(保留在图5-15中)。不幸的是,看不到我们的矩形的痕迹。问题在于,缺少一个显示的填充设置,这个矩形的默认填充是透明的,显示grid的黑色背景。让我们将其设置为喜欢的万圣节颜色:
<ControlTemplate x:Key=”ButtonTemplate”>
<Rectangle Fill=”Orange” />
</ControlTemplate>图5-15

现在我们在这个地方,如图5-16所示。
图5-16

注意,拐角处是如何成直角的?而且,一旦你点击了按钮,你不会获得压下的效果。(而且我没有意味“一个不爽的感觉”)
5.7.1控件模板和样式
注意到我们在控件模板上取得的一些成果,让我们将其复制到其它按钮上。我们可以手动设置每个按钮上的模板属性,或者,作为最普通的,我们可以用按钮的样式包装这个模板控件。如示例5-32。
示例5-32
<Window.Resources>
<Style TargetType="{x:Type Button}">

<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Fill="Orange" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

</Window.Resources>

<!-- No need to set the Template property for each button -->
<Button
x:Name="cell00" />

正如示例5-32所示,模板属性和使用样式设置是一样的。图5-17显示了结果。
图5-17

仍然,橙色是不和谐的,尤其是因为白色背景样式上的设定。我们可以用模板绑定来解决这个问题。
5.7.2模板绑定
为了回到我们的白色按钮,我们可以硬编码将矩形填充为白色,但是如果样式要改变它呢(正如在我们中断的动画)?取代以硬编码填充矩形,我们使用模板绑定来将模板应用到控件属性中,正如示例5-33所示。
示例5-33
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="White" />

<Setter Property="Template">
<Setter.Value>
<ControlTemplate x:Key="ButtonTemplate">
<Rectangle Fill="{TemplateBinding Property=Background}" />
</ControlTemplate>
</Setter.Value>
</Setter>

</Style>模板绑定就像数据绑定,除了绑定的属性来自被你替换了模板的控件(称为模板化的父级别)。在我们的情形中,像Background,HorizontalContentAlignment等等,是美丽的游戏,用来模板绑定自父级别。同时,像数据绑定,模板绑定是相当小巧的——用来保持模板中的条目属性是最新的,随着外界的属性改变,如被样式和动画设置等等。举例来说,图5-18显示了混淆矩形的Fill属性到按钮的Background属性的效果——仍然适当地通过我们的点击动画和鼠标盘旋的行为。
图5-18

尽管如此,我们还没有彻底到达。如果我们将要改变图画样品,这样图5-18已经变为了一个可玩的游戏,我们不得不显示所有的移动。为了这么做,我们需要一个内容推荐者。
5.7.3内容推荐者
如果你曾经被广告牌或汽车站长椅上写着的“这里是你的广告!”所驱动,然后这就是所有你需要知道的理解内容推荐者。内容推荐者等价于WPF中的“这里是你的内容”,允许内容由插入的ContentContainer控件保持在运行期。
在我们的情形中,内容是可视化的PlayerMove对象。取代以复制所有的工作到按钮新的控件模板中,我们只想要去除它在正确的地方。内容推荐者的工作是获取内容——由内容模板化的父级别提供,以及所有必须要显示的事物,包括样式,触发器等等。内容推荐者可以添加到你的模板中——无论在哪里看到的模板(包括多次,如果它使你愉快,例如生成一个下拉阴影)。在我们的情形中,我们在示例5-34中组成一个内容推荐者,使用第2章的技术在grid中放一个矩形。
示例5-34
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="White" />

<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Rectangle Fill="{TemplateBinding Property=Background}" />
<ContentPresenter
Content="{TemplateBinding Property=ContentControl.Content}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>

</Style>在示例5-34中,内容推荐者的Content属性绑定到ContentControl.Content属性,为了内容成功使用。作为使用样式,我们可以避免给模板绑定属性名称加上类的前缀,通过在ContentTemplate元素上设置TargetAttribute属性。
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle Fill="{TemplateBinding Property=Background}" />
<ContentPresenter
Content="{TemplateBinding Property=Content}" />
</Grid>
</ControlTemplate>进一步,在恰当的位置使用TargetType属性,你可以一起去除显示地模板绑定到Content,属性上,同时它会进行自动设置。
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle Fill="{TemplateBinding Property=Background}" />
<!-- with TargetType set, the template binding for the -->
<!-- Content property is no longer required -->
<ContentPresenter />
</Grid>
</ControlTemplate>内容推荐者是我们需要的全部,使得我们的游戏回到具有功能性,正如图5-19所示。
图5-19

5.7.4真实的工作
最后一小块工作是获取右间隙。由于内容推荐者没有自身的Padding属性,我们不能直接绑定Padding属性(它也没有Background属性,这是为什么我们使用Rectangle和其Fill属性)。因为这些属性并不匹配内容推荐者,你不得不找到映射或者组合提供这些功能的元素。例如,padding是控件中一定数量的空白,另一方面,Margin是控件周围一定数量的空白。由于他们都是同样的类型,System.Windows.Thickness,如果我们可以映射按钮中的Padding到内容控件的外面。我们的TTT游戏看起来就会很漂亮:
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="White" />
<Setter Property="Padding" Value="10,5" />

<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle Fill="{TemplateBinding Property=Background}" />
<ContentPresenter
Content="{TemplateBinding Property=Content}"
Margin="{TemplateBinding Property=Padding}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>

</Style>图5-20显示了我们最终的TTT变体。
图5-20

就像Padding和Margin间的映射,建立一个元素提供给你想要的外观,并且从父级别的模板绑定到相应的属性,将要做很多的工作来创建你自己的控件模板。
《Programming WPF》翻译 第5章 7.控件模板的更多相关文章
- 【WPF学习】第五十九章 理解控件模板
最近工作比较忙,未能及时更新内容,敬请了解!!! 对于可视化树的分析引出了几个有趣问题.例如,控件如何从逻辑树表示扩张成可视化树表示? 每个控件都有一个内置的方法,用于确定如何渲染控件(作为一组更基础 ...
- WPF笔记(1.9 样式和控件模板)——Hello,WPF!
原文:WPF笔记(1.9 样式和控件模板)--Hello,WPF! 资源的另一个用途是样式设置: <Window > <Window.Resources> <St ...
- WPF中Expander的用法和控件模板详解
一.Expander的用法 在WPF中,Expander是一个很实用的复合控件,可以很方便的实现下拉菜单和导航栏等功能.先介绍简单的用法,而后分析他的控件模板. <Window.Resource ...
- WPF教程十一:简单了解并使用控件模板
WPF教程十一:简单了解并使用控件模板 这一章梳理控件模板,每个WPF控件都设计成无外观的,但是行为设计上是不允许改变的,比如使用Button的控件时,按钮提供了能被点击的内容,那么自由的改变控件外观 ...
- Jquery如何序列化form表单数据为JSON对象 C# ADO.NET中设置Like模糊查询的参数 从客户端出现小于等于公式符号引发检测到有潜在危险的Request.Form 值 jquery调用iframe里面的方法 Js根据Ip地址自动判断是哪个城市 【我们一起写框架】MVVM的WPF框架(三)—数据控件 设计模式之简单工厂模式(C#语言描述)
jquery提供的serialize方法能够实现. $("#searchForm").serialize();但是,观察输出的信息,发现serialize()方法做的是将表单中的数 ...
- 【WPF学习】第六十章 创建控件模板
经过数十天的忙碌,今天终于有时间写博客. 前面一章通过介绍有关模板工作方式相关的内容,同时介绍了FrameWorkElement下所有控件的模板.接下来将介绍如何构建一个简单的自定义按钮,并在该过程中 ...
- WPF布局之让你的控件随着窗口等比放大缩小,适应多分辨率满屏填充应用
一直以来,我们设计windows应用程序,都是将控件的尺寸定好,无论窗体大小怎么变,都不会改变,这样的设计对于一般的应用程序来说是没有问题的,但是对于一些比较特殊的应用,比如有背景图片的,需要铺面整个 ...
- WPF自定义控件与样式(7)-列表控件DataGrid与ListView自定义样式
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: Dat ...
- WPF自定义控件与样式(9)-树控件TreeView与菜单Menu-ContextMenu
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 菜单M ...
随机推荐
- 用JUNCTION映射文件夹内容 解决多系统跑同一个虚拟机而共享文件夹路径不同的问题
事情由来: 某机器安装了俩系统,WIN7X64用来玩PC游戏,WIN2012R2用来工作,系统分别在两个不同的分区,但进入到系统后,两个系统的系统盘都是C盘.换句话说,在WIN7里,分区1是C盘,分区 ...
- 1645: [Usaco2007 Open]City Horizon 城市地平线
1645: [Usaco2007 Open]City Horizon 城市地平线 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 315 Solved: ...
- sizeof(long)
16位系统:long是4字节,int是2字节32位系统:long是4字节,int是4字节64位系统:long是8字节,int是4字节
- 自己意淫的一个简陋的Python网站扫描器
使用的模块 threading.optparse.urllib2 本地需要放字典,名字需大写. 上代码 def request(url,pathName): try: import urllib2 p ...
- jQuery的ajax jsonp跨域请求
了解:ajax.json.jsonp.“跨域”的关系 要弄清楚以上ajax.json.jsonp概念的关系,我觉得弄清楚ajax是“干什么的”,“怎么实现的”,“有什么问题”,“如果解决存在的问题”等 ...
- Java 反射 方法调用
在使用Java 反射时,对方法的调用,可能碰到最多的问题是,方法的变量如何使用.其实,调用方法的变量全部在参数数组里,不管有多少个参数,你都要把它放在参数数组里,如果是单个非数组参数,则可不使用参数数 ...
- C++11中正則表達式測试
VC++2010已经支持regex了, 能够用来编译下述代码. #include <string> #include <regex> #include <iostream ...
- LoadRunner录制回放脚本RecContentType=application/json报错
今天做一个新项目,项目系统的框架是用SSH,特意查看了一下项目源码,用的ajax提交比较多,主要的问题是该系统对IE(8~10)浏览器都不兼容,无法进行录制. 是问题,总有解决的办法! 我本机为Loa ...
- 使用android-resource-remover删除项目中无用的资源,减少包的大小
写这篇文章的原因是,一个CSDN的资源链接,Android程序员必备精品资源,在该链接的实用工具集锦中有一个工具吸引了我的注意,那就是android-resource-remover,它的解释是:一个 ...
- ASP.NET中在线用户统计
统计在线用户的作用不言而喻,就是为了网站管理者可以知道当前用户的多少,然后根据用户数量来观察服务器或者程序的性能,从而可以直观的了解到网站的吸引力或者网站程序的效率.现在,我们就介绍一个简单明了的方法 ...