原文:《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. Linux下cut命令用法

    1 一两句话描述一下cut命令吧! 正如其名,cut的工作就是“剪”,具体的说就是在文件中负责剪切数据用的. cut是以每一行为一个处理对象的,这种机制和sed是一样的.(关于sed的入门文章将在近期 ...

  2. 符号表实现(Symbol Table Implementations)

    符号表的实现有很多方式,下面介绍其中的几种. 乱序(未排序)数组实现 这种情况,不需要改变数组,操作就在这个数组上执行.在最坏的情况下插入,搜索,删除时间复杂度为O(n). 有序(已排序)数组实现 这 ...

  3. php 实现购物车

    <?php class Cart{     public function Cart() {         if(!isset($_SESSION['cart'])){             ...

  4. 有关JAVA基础学习中的集合讨论

        很高兴能在这里认识大家,我也是刚刚接触后端开发的学习者,相信很多朋友在学习中都会遇到很多头疼的问题,希望我们都能够把问题分享出来,把自己的学习思路整理出来,我们一起探讨一起成长.    今天我 ...

  5. Timus 1796. Amusement Park 聪明题

    On a sunny Sunday, a group of children headed by their teacher came to an amusement park. Aunt Frosy ...

  6. 同一台电脑启动两个或多个tomcat

    今天要在机子的tomcat上部署新的项目,需要访问的端口为80,与之前不同. 但要求不能更改原tomcat部署项目的端口,因为该tomcat内的项目正在对外使用中,且不能断开服务器. 那么,我就需要再 ...

  7. JavaScript 之 call apply bind

    关键字 this 绑定的方法 this的动态切换,固然为JavaScript创造了巨大的灵活性,但也使得编程变得困难和模糊.有时,需要把this固定下来,避免出现意想不到的情况.JavaScript提 ...

  8. EF数据建模(一)

    大中型软件开发过程中常会使用ORM技术,ORM全称是“对象-关系映射Object-Relation-Mappping”.是将数据库中的数据对象的形式表现出来,并将通过面向对象的方式将这些对象组织起来, ...

  9. QQ在线联系代码

    添加图文模块,标题地址:tencent://message/?uin=你的QQ号&Site=myqq&Menu=yes "你的QQ号"就写您自己的Q号 图片地址写: ...

  10. Gradle 编译时选择不同的 google-services.json

    在做的安卓应用需要在 debug 和 release build中使用不同的谷歌服务账号,要用到不同的google-serivces.json ,手动替换的话太费时费力,好在万能的gradle可以完成 ...