WPF ControlTemplate简介

一、简介

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(‘ ‘, 4);
                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;
        }
时间: 2024-08-11 09:05:56

WPF ControlTemplate简介的相关文章

Introduction to WPF Templates(WPF模板简介)

Introduction(简介) Windows Presentation Foundation allows the developer to completely change the look and feel of the controls. This is accomplished by using Control Templates. It means you can render your Button as an Ellipse which when hovered will c

WPF ControlTemplate

ControlTemplate:控件模板,顾名思义也就是定制特定的控件供公共调用,有点类似WinForm中对一些通用控件进行重写使用. ControlTemplate:控件模板主要有两个重要属性:VisualTree内容属性和Triggers触发器.定义控件模板也是对控件的视觉树和触发器进行重新定义,属性可以依赖原有控件的属性,只是根据需要调整的部分属性, 在Xaml文件的Resources中定义需要使用的模板,在需要使用模板的控件中将Template赋值为相应的控件模板x:key值实现控件的重

WPF ControlTemplate 控件模板

http://www.cnblogs.com/zhouyinhui/archive/2007/03/28/690993.html 模板与样式 它们可以调整控件的属性,但是样式不能使用全新的由不同元素组成的可视化树替代控件原来的外观. <Window x:Class="ApplyTemplateToControl.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quo

ASP.NET Connections大会上我做的讲座的讲义: WPF/E,LINQ和ASP.NET技巧/诀窍

摘要:ASP.NET Connections大会上我做的讲座的讲义: WPF/E,LINQ和ASP.NET技巧/诀窍 [原文位址]Slides from my ASP.NET Connections talks: WPF/E, LINQ and ASP.NET Tips/Tricks [原文发表日期] Friday, March 30, 2007 11:28 PM 这个星期早些时候,我在奥兰多举行的ASP.NET Connections大会上做了三场讲座.下面是我做的三场讲座的讲义/Demo程序

Visual Basic 2010 2012 2013 从入门到精通

Visual Basic 2010 2012 2013 从入门到精通 VB一直以来以简单易用,功能强大,而深受广大编爱好者的青睐.而继VB6.0后,发布的VB.net可以说是具有划时代意义的产品,其在保留原有易用性的基础上,高速增强其功能.现如今VB的程序已经完全可以用VB.net来开发与C++.Java相抗衡的软件产品.最新版本的Visual Basic 2010,其功能的强大,可以说是有史以来最强悍版本,也是一套可以与任何一套编程语言相媲美的产品.在国外,更是受前所未有欢迎.本站教程为无限升

WPF的ControlTemplate和DataTemplate简介

首先理清几个概念,Template.ControlTemplate.ContentTemplate.DataTemplate.ContentControl 这几个东西名字都差不多,意思感觉也接近,初次接触真的难以理解,那么现在开始区分了: 1.子类: ContentControl是Control的子类,专门用于显示内容的,如常用的Label就是ContentControl的子类 2.属性: Template 是Control类的一个属性: ContentTemplate是ContentContr

WPF Template模版之DataTemplate与ControlTemplate【一】

WPF Template模版之DataTemplate与ControlTemplate[一] 标签: Wpf模版 2015-04-19 11:52 510人阅读 评论(0) 收藏 举报  分类: -------1.5 .NET(25)  版权声明:本文为博主郎涯工作室原创文章,未经博主允许不得转载. 目录(?)[+] WPF系统不但支持传统的Winfrom编程的用户界面和用户体验设计,更支持使用专门的设计工具Blend进行专业设计,同时还推出了以模板为核心的新一代设计理念. 1. 模板的内涵 作

WPF中ControlTemplate和DataTemplate的区别

下面代码很好的解释了它们之间的区别: <Window x:Class="WPFTestMe.Window12" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window12" Height="300&q

WPF Template模版之DataTemplate与ControlTemplate的关系和应用【二】

1. DataTemplate和ControlTemplate的关系 学习过DataTemplate和ControlTemplate,你应该已经体会到,控件只是数据的行为和载体,是个抽象的概念,至于它本身长成什么样子(控件内部结构),它的数据会长成什么样子(数据显示结构)都是靠Template生成的.决定控件外观的是ControlTemplate,决定数据外观的是DataTemplate,它们正是Control类的Template和ContentTemplate两个属性值 凡是Template,