一、简介

WPF包含数据模板和控件模板,其中控件模板又包括ControlTemplate和ItemsPanelTemplate,这里讨论一下ControlTemplate。
其实WPF的每一个控件都有一个默认的模板,该模板描述了控件的外观以及外观对外界刺激所做出的反应。我们可以自定义一个模板来替换掉控件的默认模板以便打造个性化的控件。
与Style不同,Style只能改变控件的已有属性值(比如颜色字体)来定制控件,但控件模板可以改变控件的内部结构(VisualTree,视觉树)来完成更为复杂的定制,比如我们可以定制这样的按钮:在它的左半部分显示一个小图标而它的右半部分显示文本。
要替换控件的模板,我们只需要声明一个ControlTemplate对象,并对该ControlTemplate对象做相应的配置,然后将该ControlTemplate对象赋值给控件的Template属性就可以了。

二、ControlTemplate包含两个重要的属性

VisualTree,该模板的视觉树,其实我们就是使用这个属性来描述控件的外观的。
Triggers,触发器列表,里面包含一些触发器Trigger,我们可以定制这个触发器列表来使控件对外界的刺激发生反应,比如鼠标经过时文本变成粗体等。

三、实例

1、定制可视化树(VisualTree)

       <Button>
<Button.Template>
<ControlTemplate>
<!--定义视觉树-->
<Grid>
<Ellipse Name="faceEllipse"
Width="{TemplateBinding Button.Width}"
Height="{TemplateBinding Control.Height}"
Fill="{TemplateBinding Button.Background}"/>
<TextBlock Name="txtBlock"
Margin="{TemplateBinding Button.Padding}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Text="{TemplateBinding Button.Content}" />
</Grid>
<!--定义视觉树_end-->
</ControlTemplate>
</Button.Template>
comtroltemplate_test
</Button>

代码效果:

在上面的代码中,我们修改了Button的Template属性,我们定义了一个ControlTemplate,在<ControlTemplate> ... </ControlTemplate>之间包含的是模板的视觉树,也就是如何显示控件的外观,我们这里使用了一个Ellipse(椭圆)和一个TextBlock(文本块)来定义控件的外观。
很容易联想到一个问题:控件(Button)的一些属性,比如高度、宽度、文本等如何在新定义的外观中表现出来呢?
我们使用TemplateBinding 将控件的属性与新外观中的元素的属性关联起来Width="{TemplateBinding Button.Width}" ,这样我们就使得椭圆的宽度与按钮的宽度绑定在一起而保持一致,同理我们使用Text="{TemplateBinding Button.Content}"将TextBlock的文本与按钮的Content属性绑定在一起。

2、定制触发器Triggers

    <Button Grid.Row="1" Grid.Column="0" Margin="10">
<Button.Template>
<ControlTemplate>
<!--定义视觉树-->
<Grid>
<Ellipse Name="faceEllipse"
Width="{TemplateBinding Button.Width}"
Height="{TemplateBinding Control.Height}"
Fill="{TemplateBinding Button.Background}"/>
<TextBlock Name="txtBlock"
Margin="{TemplateBinding Button.Padding}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Text="{TemplateBinding Button.Content}" />
</Grid>
<!--定义视觉树_end-->
<!--定义触发器-->
<ControlTemplate.Triggers>
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter Property="Button.Foreground" Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
<!--定义触发器_End-->
</ControlTemplate>
</Button.Template>
comtroltemplate_test
</Button>

代码效果:

在上面的代码中注意到<ControlTemplate. Triggers> ... </ControlTemplate. Triggers> 之间的部分,我们定义了触发器 <Trigger Property="Button.IsMouseOver" Value="True">,其表示当我们Button的IsMouseIOver属性变成True时,将使用设置器<Setter Property="Button. Foreground" Value="Red" /> 来将Button的Foreground属性设置为Red。这里有一个隐含的意思是:当Button的IsMouseIOver属性变成False时,设置器中设置的属性将回复原值。

3、ControlTemplate的重用

你只需要将模板定义为资源,其实大多数情况下,我们也是这样做的。

<Window.Resources>
<ControlTemplate TargetType="Button" x:Key="ButtonTemplate">
<!--定义视觉树-->
<Grid>
<Ellipse Name="faceEllipse"
Width="{TemplateBinding Button.Width}"
Height="{TemplateBinding Control.Height}"
Fill="{TemplateBinding Button.Background}"/>
<TextBlock Name="txtBlock"
Margin="{TemplateBinding Button.Padding}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Text="{TemplateBinding Button.Content}" />
</Grid>
<!--定义视觉树_end-->
<!--定义触发器-->
<ControlTemplate.Triggers>
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter Property="Button.Foreground" Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
<!--定义触发器_End-->
</ControlTemplate>
</Window.Resources> 

上面的代码将我们原来的模板定义为窗体范围内的资源,其中TargetType="Button"指示我们的模板作用对象为Button,其中的ButtonTemplate是我们定义的模板的x:Key。
这样在整个窗体范围内的按钮都可以使用这个模板了,模板的使用方法也很简单:

<Button Grid.Column="0" Template="{StaticResource ButtonTemplate}" Content="comtroltemplate_test"/>
<Button Grid.Column="1" Template="{StaticResource ButtonTemplate}" Content="test btn2" />
<Button Grid.Column="2" Template="{StaticResource ButtonTemplate}" Content="test btn3" />

代码效果:

4、在trigger中使用storyboard,事件响应中添加的动画效果

<Window.Resources>
<ControlTemplate TargetType="Button" x:Key="ButtonTemplate">
<!--定义视觉树-->
<Grid>
<Ellipse Name="faceEllipse"
Width="{TemplateBinding Button.Width}"
Height="{TemplateBinding Control.Height}"
Fill="{TemplateBinding Button.Background}"/>
<TextBlock Name="txtBlock"
Margin="{TemplateBinding Button.Padding}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Text="{TemplateBinding Button.Content}" />
</Grid>
<!--定义视觉树_end-->
<!--定义动画资源-->
<ControlTemplate.Resources>
<Storyboard x:Key="MouseClickStoryboard">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="faceEllipse" Storyboard.TargetProperty="Width" BeginTime="00:00:00">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="50"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.3" Value="100"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<!--定义动画资源_end-->
<!--定义触发器-->
<ControlTemplate.Triggers>
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter Property="Button.Foreground" Value="Red" />
</Trigger>
<EventTrigger RoutedEvent="Mouse.MouseDown" SourceName="faceEllipse">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResourceMouseClickStoryboard}"/>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseDown" SourceName="txtBlock">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource MouseClickStoryboard}"/>
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>
<!--定义触发器_End-->
</ControlTemplate>
</Window.Resources>

四、获取.Net中原生控件的的默认ControlTemplate

我们知道每个控件都有自己默认的模板,这是MS编写的,如果我们能够得到这些模板的XAML代码,那么它将是学习模板的最好的示例,
要想获得某个控件ctrl的默认模板,请调用以下方法:

string GetTemplateXamlCode(Control ctrl)
{
string xaml = "no template";
FrameworkTemplate template = ctrl.Template;
if (template != null)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = new string(' ', );
settings.NewLineOnAttributes = true; StringBuilder strbuild = new StringBuilder();
XmlWriter xmlwrite = XmlWriter.Create(strbuild, settings); try
{
XamlWriter.Save(template, xmlwrite);
xaml = strbuild.ToString();
}
catch (Exception exc)
{
xaml = exc.Message;
}
} return xaml;
}

[No0000DA]WPF ControlTemplate简介的更多相关文章

  1. 深入详解WPF ControlTemplate

    WPF包含数据模板和控件模板,其中控件模板又包括ControlTemplate和ItemsPanelTemplate,这里讨论一下WPF ControlTemplate. 其实WPF的每一个控件都有一 ...

  2. Wpf 数据绑定简介、实例1

    简介:1.WPF绑定使用的源属性必须是依赖项属性,这是因为依赖项属性具有内置的更改通知支持,元素绑定表达式使用了Xaml扩展标记, WPF绑定一个控件是使用Binding.ElementName, 绑 ...

  3. WPF ControlTemplate

    ControlTemplate:控件模板,顾名思义也就是定制特定的控件供公共调用,有点类似WinForm中对一些通用控件进行重写使用. ControlTemplate:控件模板主要有两个重要属性:Vi ...

  4. WPF : ControlTemplate和DataTemplate的区别

    ControlTemplate用于描述控件本身. 使用TemplateBinding来绑定控件自身的属性, 比如{TemplateBinding Background}DataTemplate用于描述 ...

  5. WPF ControlTemplate 动画板 结束事件不触发

    解决此问题很简单 将Storyboard单独提取出来及可 给定Key名称,然后在触发器中的BeginStoryboard的storyboard绑定即可 <!--单独提取并设置Xkey--> ...

  6. WPF开发简介教程

    1/ VS中文件-新建-项目-WPF应用程序 2/ 左上角工具箱中有很多组件可以直接拖拽使用 3/ 双击组件,进入脚本功能编辑界面,如按钮: private void Button_Click_1(o ...

  7. WPF ControlTemplate,DataTemplate

    The Control Template defines the visual appearance of a control. All of the UI elements have some ki ...

  8. WPF DataTemplate與ControlTemplate

    一. 前言     什麼是DataTemplate? 什麼是ControlTemplate? 在stackoverflow有句簡短的解釋 "A DataTemplate, therefore ...

  9. wpf的控件style

    前段时间一直在做wpf的UI开发,每次想做些控件style定制的时候都很头疼 很多控件不知道他的controltemplate是什么样的 为了方便大家写style 特别奉上wpf的style大全 从此 ...

随机推荐

  1. 那天有个小孩教我WCF[一][2/3]

    接着上次的继续讲吧 我们开始吧 9.创建数据库 use master go --创建库 if exists(select * from sysdatabases where name='NewsDB' ...

  2. [转]MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码

    本文转自:http://www.cnblogs.com/guomingfeng/p/mvc-ef-t4.html 〇.目录 一.前言 二.工具准备 三.T4代码生成预热 (一) 单文件生成:Hello ...

  3. Boost中的智能指针(转)

    这篇文章主要介绍 boost中的智能指针的使用.(转自:http://www.cnblogs.com/sld666666/archive/2010/12/16/1908265.html) 内存管理是一 ...

  4. TitleBar 的那些设置

    设置状态栏透明: View decorView = activity.getWindow().getDecorView(); int option = View.SYSTEM_UI_FLAG_LAYO ...

  5. 菜鸟教程之工具使用(八)——EGit禁止自动转换回车换行符

    众所周知,Windows和Linux系统的回车换行是不一样的.想要进一步了解它们的可以阅读下面的介绍,不感兴趣的可以直接跳过. 产生背景 关于“回车”(carriage return)和“换行”(li ...

  6. vue cli 项目的提交

    前提: 配置git.以及git的ssh key信息 假设已经都安装好了,此处我用vue项目为例,因为vue-cli已经默认为我生成了ignore文件 在项目目录 初始化本地仓库,会创建一个.git目录 ...

  7. 【iCore1S 双核心板_FPGA】例程五:Signal Tapll 实验——逻辑分析仪

    核心代码: //--------------------Module_Signal_TapII-------------------// module Signal_TapII( input CLK_ ...

  8. ODbgScript 2.01帮助文档

    -------------------------------ODbgScript original pluginhttp://github.com/odbgscript--------------- ...

  9. Java知多少(49)throw:异常的抛出

    到目前为止,你只是获取了被Java运行时系统抛出的异常.然而,程序可以用throw语句抛出明确的异常.Throw语句的通常形式如下:    throw ThrowableInstance;这里,Thr ...

  10. msyql同步的时候报错 : 错误代码: 1293 Incorrect table definition;there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause

    场景,两个不同服务器上的数据库,进行数据库同步 但是执行之后,提示报错 错误代码: 1293 Incorrect table definition; there can be only one TIM ...