原文:《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.控件模板的更多相关文章

  1. 【WPF学习】第五十九章 理解控件模板

    最近工作比较忙,未能及时更新内容,敬请了解!!! 对于可视化树的分析引出了几个有趣问题.例如,控件如何从逻辑树表示扩张成可视化树表示? 每个控件都有一个内置的方法,用于确定如何渲染控件(作为一组更基础 ...

  2. WPF笔记(1.9 样式和控件模板)——Hello,WPF!

    原文:WPF笔记(1.9 样式和控件模板)--Hello,WPF! 资源的另一个用途是样式设置: <Window >  <Window.Resources>    <St ...

  3. WPF中Expander的用法和控件模板详解

    一.Expander的用法 在WPF中,Expander是一个很实用的复合控件,可以很方便的实现下拉菜单和导航栏等功能.先介绍简单的用法,而后分析他的控件模板. <Window.Resource ...

  4. WPF教程十一:简单了解并使用控件模板

    WPF教程十一:简单了解并使用控件模板 这一章梳理控件模板,每个WPF控件都设计成无外观的,但是行为设计上是不允许改变的,比如使用Button的控件时,按钮提供了能被点击的内容,那么自由的改变控件外观 ...

  5. Jquery如何序列化form表单数据为JSON对象 C# ADO.NET中设置Like模糊查询的参数 从客户端出现小于等于公式符号引发检测到有潜在危险的Request.Form 值 jquery调用iframe里面的方法 Js根据Ip地址自动判断是哪个城市 【我们一起写框架】MVVM的WPF框架(三)—数据控件 设计模式之简单工厂模式(C#语言描述)

    jquery提供的serialize方法能够实现. $("#searchForm").serialize();但是,观察输出的信息,发现serialize()方法做的是将表单中的数 ...

  6. 【WPF学习】第六十章 创建控件模板

    经过数十天的忙碌,今天终于有时间写博客. 前面一章通过介绍有关模板工作方式相关的内容,同时介绍了FrameWorkElement下所有控件的模板.接下来将介绍如何构建一个简单的自定义按钮,并在该过程中 ...

  7. WPF布局之让你的控件随着窗口等比放大缩小,适应多分辨率满屏填充应用

    一直以来,我们设计windows应用程序,都是将控件的尺寸定好,无论窗体大小怎么变,都不会改变,这样的设计对于一般的应用程序来说是没有问题的,但是对于一些比较特殊的应用,比如有背景图片的,需要铺面整个 ...

  8. WPF自定义控件与样式(7)-列表控件DataGrid与ListView自定义样式

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: Dat ...

  9. WPF自定义控件与样式(9)-树控件TreeView与菜单Menu-ContextMenu

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 菜单M ...

随机推荐

  1. 用JUNCTION映射文件夹内容 解决多系统跑同一个虚拟机而共享文件夹路径不同的问题

    事情由来: 某机器安装了俩系统,WIN7X64用来玩PC游戏,WIN2012R2用来工作,系统分别在两个不同的分区,但进入到系统后,两个系统的系统盘都是C盘.换句话说,在WIN7里,分区1是C盘,分区 ...

  2. 1645: [Usaco2007 Open]City Horizon 城市地平线

    1645: [Usaco2007 Open]City Horizon 城市地平线 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 315  Solved: ...

  3. sizeof(long)

    16位系统:long是4字节,int是2字节32位系统:long是4字节,int是4字节64位系统:long是8字节,int是4字节

  4. 自己意淫的一个简陋的Python网站扫描器

    使用的模块 threading.optparse.urllib2 本地需要放字典,名字需大写. 上代码 def request(url,pathName): try: import urllib2 p ...

  5. jQuery的ajax jsonp跨域请求

    了解:ajax.json.jsonp.“跨域”的关系 要弄清楚以上ajax.json.jsonp概念的关系,我觉得弄清楚ajax是“干什么的”,“怎么实现的”,“有什么问题”,“如果解决存在的问题”等 ...

  6. Java 反射 方法调用

    在使用Java 反射时,对方法的调用,可能碰到最多的问题是,方法的变量如何使用.其实,调用方法的变量全部在参数数组里,不管有多少个参数,你都要把它放在参数数组里,如果是单个非数组参数,则可不使用参数数 ...

  7. C++11中正則表達式測试

    VC++2010已经支持regex了, 能够用来编译下述代码. #include <string> #include <regex> #include <iostream ...

  8. LoadRunner录制回放脚本RecContentType=application/json报错

    今天做一个新项目,项目系统的框架是用SSH,特意查看了一下项目源码,用的ajax提交比较多,主要的问题是该系统对IE(8~10)浏览器都不兼容,无法进行录制. 是问题,总有解决的办法! 我本机为Loa ...

  9. 使用android-resource-remover删除项目中无用的资源,减少包的大小

    写这篇文章的原因是,一个CSDN的资源链接,Android程序员必备精品资源,在该链接的实用工具集锦中有一个工具吸引了我的注意,那就是android-resource-remover,它的解释是:一个 ...

  10. ASP.NET中在线用户统计

    统计在线用户的作用不言而喻,就是为了网站管理者可以知道当前用户的多少,然后根据用户数量来观察服务器或者程序的性能,从而可以直观的了解到网站的吸引力或者网站程序的效率.现在,我们就介绍一个简单明了的方法 ...