WPF(四)举例讲解WPF控件模版
WPF的每一个控件都有一个默认的模板,该模板描述了控件的外观以及外观对外界刺激所做出的反应。我们可以自定义一个模板来替换掉控件的默认模板以便打造个性化的控件。
与Style不同,Style只能改变控件的已有属性值(比如颜色字体)来定制控件,但控件模板可以改变控件的内部结构(VisualTree,视觉树)来完成更为复杂的定制。
要替换控件的模板,我们只需要声明一个ControlTemplate对象,并对该ControlTemplate对象做相应的配置,然后将该ControlTemplate对象赋值给控件的Template属性就可以了。
ControlTemplate包含两个重要的属性:
1,VisualTree,该模板的视觉树,其实我们就是使用这个属性来描述控件的外观的
2,Triggers,触发器列表,里面包含一些触发器Trigger,我们可以定制这个触发器列表来使控件对外界的刺激发生反应,比如鼠标经过时文本变成粗体等。
一:Understanding Logical Trees and Visual Trees 理解逻辑树和视觉树
(1) 视觉树
(2) 逻辑树
LogicalTreeHelper Methods逻辑树辅助方法
Name | Description |
FindLogicalNode() | 查找某一特定元素的名字,开始在指定部分搜索下面的逻辑树。 |
BringIntoView() | Scrolls an element into view。The FrameworkElement.BringIntoView() method performs the same trick. |
GetParent() | 取得父元素具体内容 |
GetChildren() | 取得子元素的一个具体内容 |
<Button.Template>
<ControlTemplate>
<!--定义视觉树-->
<Grid>
… …
</Grid>
<!--定义视觉树_end-->
</ControlTemplate>
在<ControlTemplate> ... </ControlTemplate>之间包含的是模板的视觉树,也就是如何显示控件的外观
二:Creating Control Templates 创建控件模版
<Window.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Border BorderBrush="Orange" BorderThickness="3" CornerRadius="2" Background="Red" TextBlock.Foreground="White"></Border>
</ControlTemplate>
</Window.Resources>
<StackPanel Margin="5">
<Button Padding="5" Margin="5" Template="{StaticResource ButtonTemplate}">Template Button</Button>
<Button Padding="5" Margin="5">Second Button</Button>
</StackPanel>
ControlTemplate定义模版
TargetType使用哪个的模版
Template="{StaticResource 模版名称} 控件调用模版
三:Template Bindings 模版绑定
<ControlTemplate>
<Grid>
<TextBlock Name="txtBlock" Margin="{TemplateBinding Button.Padding}" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{TemplateBinding Button.Content}" />
</Grid>
</ControlTemplate>
属性="{TemplateBinding 模版属性}"
使用TemplateBinding 将控件的属性与新外观中的元素的属性关联起来,Text="{TemplateBinding Button.Content}",这样我们就使得TextBlock的Text与按钮的Content绑定在一起而保持一致,
Text="{TemplateBinding Button.Content}"
四:Template Triggers 模版触发器
<!--定义触发器-->
<ControlTemplate.Triggers>
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter Property="Button.Foreground" Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
<!--定义触发器_End-->
当事件Button.IsMouseOver= True时执行Button.Foreground= Red
这里有一个隐含的意思是:当Button的IsMouseIOver属性变成False时,设置器中设置的属性将回复原值。
五:Organizing Template Resources模版资源组管理
虽然你可以把所有的模板弄成一个单一的资源字典文件, 经验丰富的程序员更愿意为每个控制模板创建一个单独的资源字典。
(1) 创建资源字典,取名叫Button,定义控件模版
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
</ControlTemplate>
</ResourceDictionary>
(2) 调用
<Application x:Class="SimpleApplication.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Button.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
六:Refactoring the Button Control Template 重构按钮控制模版
设置好几种属性,定义好名字,控件的属性可以直接绑定到该属性上。如:
定义属性:
<RadialGradientBrush RadiusX="1" RadiusY="5" GradientOrigin="0.5,0.3"
x:Key="Border">
<GradientStop Color="White" Offset="0" />
<GradientStop Color="Blue" Offset="1" />
</RadialGradientBrush>
绑定属性:
<ControlTemplate x:Key="GradientButtonTemplate" TargetType="{x:Type Button}">
<Border Name="Border" BorderBrush="{StaticResource Border}"
… …
… …
七:Applying Templates with Styles 应用模版风格
先定义控件模版的属性为控件本身默认属性,再通过Style进行风格设置。
定义属性:
Background="{TemplateBinding Background}"
属性名字= "{TemplateBinding 属性名字}"
设置:
<Style x:Key="CustomButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Control.Template" Value="{StaticResource CustomButtonTemplate}"></Setter>
</Style>
八:Applying Templates Automatically 自动应用模版
设置个模版,不定义名字,用的时候名字取Null
先设置个样式:
<Style TargetType="{x:Type Button}">
<Setter Property="Control.Template" Value="{StaticResource ButtonTemplate}"
</Style>
我们要取消自动应用这个样式,可以这样写:
<Button Style="{x:Null}" ... ></Button>
九:User-Selected Skins 用户选择皮肤
引用资源字典,然后就可以NEW个新的,重新选择资源字典,相当于在换皮肤了,因为样式和控件模版都可以放在资源字典里面。
(1):
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/GradientButton.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
(2):
ResourceDictionary newDictionary = new ResourceDictionary();
newDictionary.Source = new Uri( "Resources/GradientButtonVariant.xaml", UriKind.Relative);
this.Resources.MergedDictionaries[0] = newDictionary;