原文:《深入浅出WPF》笔记——模板篇

我们通常说的模板是用来参照的,同样在WPF中,模板是用来作为制作控件的参照。

一、认识模板

1.1WPF菜鸟看模板

  前面的记录有提过,控件主要是算法和数据的载体。控件的算法主要体现在可以激发的事件、可以调用的方法、能进行的操作等方面;控件的数据体现为:控件能展示哪些数据。上面两方面终决定了控件,在以前的GUI界面上面,或者是Winform上面,控件的数据和功能耦合的太紧密,如果控件想以不同格式显示数据的话,由于控件的形状基本上都固定了,只有重新去自定义控件,以适合数据的显示格式。在WPF中,就可以让模板出马了,如果你让数据以不同的格式显示,那么直接在数据的外衣——DataTemplate里面定义一些控件,安排好布局,到用的时间,直接给拥有数据的控件穿上衣服,数据控件上面就会参照着我们的模板来显示数据了。当然还有一种情况,我们想让一种控件的显示稍作一点修改,由于传统的控件的主要问题就是耦合性太强,才不易控制,在WPF中,一个控件,可能是多个控件的合体,这样我们就相对更容易控制它。由于控件可以拆分,那么在控件里面添加一个控件或者是对某些控件的属性做些修改,就不需要重新定义控件,只需要定义一个ControlTemlate,然后让其装在Style里面,最后让控件拥有Style——那么控件就会照着ControlTemplate里面的定义来显示。

1.2容易弄乱的几个单词区分

  由于模板系列的单词很相像,很容易弄乱掉,所以我觉得还是很有必要把几个单词做简要的说明。在区分之前,还是先了解一下Style,因为Style与ControlTemplate的联系比较紧密,为了防止思路死锁,在此稍作说明,具体的用法会在后面详细记录。Style是风格,对于一个风格,为了不至于有的控件使用该风格搞成四不像,如你让涛哥天天穿个背心去开会,那还得了,一定是要穿的庄重吧,同样控件也是如此,要定义风格要有适合的类,也即要定义其目标类型,然后根据目标的属性来定义风格的具体内容。下面给出一个简要的风格定义:

<Style x:Key="RoundCornerTextBoxStyle" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
                          Background="{TemplateBinding Background}" CornerRadius="10" SnapsToDevicePixels="true">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

  接着解释一下上面风格的含义:一个风格如果作为资源可以供多个控件使用的话,就可以使用x:key,BaseOn获取或设置为当前样式的基类型中定义的样式,基类型中有定义,目标类型没有定义的话,会使用基类型的样式。TargetType是目标类型,对于简单的Setter可以直接写成<Setter Property="属性值" Value=“对应的属性值”/>对于复杂的可以通过内容标签的写法如: <Setter Property="BorderBrush" Value="Red"/>就是设置笔刷属性为红色,上面的代码中是设置控件的Template属性,为ControlTemplate类型的值,其中TemplateBinding为绑定目标控件的属性,可以说TemplateBinding是控件专用的,其他和Binding保持一致。

稍微了解了Style之后再来看DataTemplate和ControlTemplate,他们是控件属性的类型。具体的如下:

ControlTemplate类的代表:

  • ContentControl类型的Template属性,例如Button为ContentControl类
  • ItemsControl类型的Template属性,例如ListBox为ItemsControl类

关于两种类型的元素具体可以参考控件和布局的记录。

DataTemplate的典型代表:

  • ContentControl类型的ContentTemplate属性
  • ItemsControl类型的ItemTemplate属性
  • Gridview的行中的CellTemplate属性

是不是有点乱了,下面给出一个草图(图1)来表述一下,下面的例子中可能会遇到很多类型名和属性容易混淆的地方,可以回头看一下。

图1

二、数据的外衣DataTemplate

  在实际的UI设计中,可能会经常遇到,把已知的数据,通过一定的格式或者是按照一定的排列显示出来,DataTemplate正是解决这样的问题的模板,然后直接把DataTemplate利用空间的属性穿在身上了,最终控件中的数据就会按照一定的排列显示了,最终上了舞台。下面就通过实例来演示一下DataTemplate,该实例涉及到的内容可能比较多,主要包含绑定、资源、ItemsControl、Converter等的使用,如果不懂的话可以留言给我,好了,先看一下效果如图2:

图2

左边的是一个UserControl(继承与ContentControl),中间的是ListBox(继承与ItemsControl)。当点击ListBox的项时,可以改变左边的颜色。直接上代码了:

<Window x:Class="Chapter_09.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Chapter_09"
Title="MainWindow" Height="350" Width="450">
<Window.Resources>
<local:NoConvertImage x:Key="nci"/>
<!--定义详细模板-->
<DataTemplate x:Key="studentDetail">
<Border BorderBrush="Black" BorderThickness="1" CornerRadius="6">
<StackPanel Margin="5" Orientation="Vertical">
<Image Source="{Binding No,Converter={StaticResource nci}}" Width="250"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:" FontWeight="Bold" ></TextBlock>
<TextBlock Text="{Binding Name}"></TextBlock>
<TextBlock Text="Gender:" FontWeight="Bold" ></TextBlock>
<TextBlock Text="{Binding Sex}"></TextBlock>
<TextBlock Text="Age:" FontWeight="Bold" ></TextBlock>
<TextBlock Text="{Binding Age}"></TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="No:" FontWeight="Bold" ></TextBlock>
<TextBlock Text="{Binding No}"></TextBlock>
<TextBlock Text="Color:" FontWeight="Bold" ></TextBlock>
<TextBlock Text="{Binding Color}"></TextBlock>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
<!--定义列表模板-->
<DataTemplate x:Key="studentList">
<Grid Margin="2">
<StackPanel Orientation="Horizontal">
<Image Source="Resources/Images/月饼.png" />
<StackPanel>
<TextBlock Text="{Binding Name}"></TextBlock>
<TextBlock Text="{Binding Color}"></TextBlock>
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
</Window.Resources>
<StackPanel Orientation="Horizontal" >
<UserControl ContentTemplate ="{StaticResource studentDetail}" Content="{Binding SelectedItem,ElementName=listBox}"/>
<ListBox x:Name="listBox" ItemTemplate="{StaticResource studentList}"/>
</StackPanel>
</Window>

后台代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes; namespace Chapter_09
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//绑定ListBox和listViewItem
InitialStudentList();
}
private void InitialStudentList()
{
List <Student> studentList= new List<Student>()
{
new Student(){Name="张飞",Age=,Color="蓝色",No="",Sex="男"},
new Student(){Name="貂蝉",Age=,Color="绿色",No="",Sex="女"},
new Student(){Name="曹操",Age=,Color="红色",No="",Sex="男"},
new Student(){Name="华佗",Age=,Color="橙色",No="",Sex="男"},
new Student(){Name="赵云",Age=,Color="紫色",No="",Sex="男"}
};
this.listBox.ItemsSource = studentList;
}
} #region Student——学生类
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public string No { get; set; }
public string Sex { get; set; }
public string Color { get; set; }
}
#endregion #region 把ID转化成Uri形式
public class NoConvertImage : IValueConverter
{
#region IValueConverter 成员 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string uriImg = string.Format(@"/Resources/Images/{0}.png", (string)value);
return new BitmapImage(new Uri(uriImg, UriKind.Relative));
} public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
} #endregion
}
#endregion
}

  相对来说,后台代码都是用的以前的知识,前台XAML代码有几点要记录一下:在此处Datatemplate声明为资源,然后通过ContentTemplate,ItemTemplate属性获取到资源。在上面的例子中还有要注意的地方是:UserControl的Content="{Binding SelectedItem,ElementName=listBox}属性为Object类,所以在此绑定ListBox的选定项作为Content,在通过绑定来获取图片和人物的信息,除此还有一个要注意的,还有个是数据驱动,以前我们使用事件驱动应该是通过选项的id来得到Student实体,然后把实体的信息在详情中显示,经过的步骤比较多,可见数据驱动的好处。

三、控件的外衣——ControlTemplate

  ControlTemplate主要用于改变控件的形状,是对控件已有的形状不满意,通常借助Style来指定目标控件的Template属性来实现。下面我们就来举个例子,来以小见大。该例子是把TextBox的边框改成圆角。本例子要用到Blend工具。

首先在新建的项目主窗体中添加一个TextBox,然后通过编辑模板->编辑副本(如图3)

图3

然后通过出现一个创建Style资源,选择应用程序,以便其他控件也可以使用,如图4。之后发现转到App.xaml文件里面了。

图4

  我们暂且不去看代码的意思,我们先看对象和时间线的截图(图5)模板下面有两个控件,但是具有层次关系,这不是我们以前记录的可视树吗?所以为控件指定ControlTemplate衣服,其实就是来修改可视树上的元素。我们把Style部分的代码改为上面介绍Style时引用的代码:

图5

        <Style x:Key="TextBoxStyle1" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
                           Background="{TemplateBinding Background}" CornerRadius="10" SnapsToDevicePixels="true">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

发现现在主窗体的textBox已经变成椭圆形的了。上面的代码只是让Border代替了原来的控件。然后去掉了Style的触发器(后面会记录到)。关于ControlTemplate,重在编辑里面的元素,以及元素的属性。下面看一下效果:

图6

除了上面的两个模板之外还有个是只和ItemsControl有关的PanelTemplate:指定 ItemsPresenter 为 ItemsControl 的项的布局创建的面板.也就是指定一个承载ItemsControl的条目的面板,以便使控件的布局更加灵活。例如,我们平时见到的ListBox控件都是竖着下来的,我们下面演示一个横着排列的,其中就利用到了PanelTemplate。代码和效果如图7:

图7

此功能不是本记录的重点,所以不做过多介绍。

四、DataTeplate的另外几种用法

4.1设置DataTemplate的DataType属性  

  除了为控件指定DataTeplate,还可以不指定DataTemplate。而是在DataTemplate设置DataType属性,类似于 Style 类的 TargetType 属性的属性。 如果将此属性设置为数据类型,但没有指定 x:Key, DataTemplate 自动应用于该类型的数据对象 。下面的例子是自动的使用于ItemsControl的条目:

<Window x:Class="WpfControlTemlate.DataTypeOfDataTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfControlTemlate"
xmlns:c="clr-namespace:System.Collections;assembly=mscorlib"
Title="DataTypeOfDataTemplate" Height="300" Width="300">
<Window.Resources>
<!--会自动的根据数据类型来做适合控件的衣服-->
<DataTemplate DataType="{x:Type local:Unit}">
<Grid>
<StackPanel Orientation="Horizontal">
<Grid>
<Rectangle Stroke="Yellow" Fill="Orange" Width="{Binding Price}"/>
<TextBlock Text="{Binding Year}"/>
</Grid>
<TextBlock Text="{Binding Price}"/>
</StackPanel>
</Grid>
</DataTemplate>
<c:ArrayList x:Key="ds">
<local:Unit Year="2011年" Price="100"/>
<local:Unit Year="2010年" Price="120"/>
<local:Unit Year="2012年" Price="140"/>
<local:Unit Year="2013年" Price="160"/>
<local:Unit Year="2014年" Price="180"/>
</c:ArrayList>
</Window.Resources>
<StackPanel>
<ListBox ItemsSource="{StaticResource ds}"/>
<ComboBox ItemsSource="{StaticResource ds}" Margin="5"/>
</StackPanel>
</Window>

其中Unit的代码为:

    public class Unit
{
public int Price { get; set; }
public string Year { get; set; }
}

效果如图8:

图8

4.2DataTemplate对XML的支持

  下面两个例子为两个比较常见的例子(TreeView和Menu),只给出代码和效果图,具体用的时间可以自己去试着修改:

XML

<?xml version="1.0" encoding="utf-8" ?>
<Data xmlns="">
<Grade Name="一年级">
<Class Name="甲班">
<Group Name="A组"/>
<Group Name="B组"/>
<Group Name="C组"/>
</Class>
<Class Name="乙班">
<Group Name="A组"/>
<Group Name="B组"/>
<Group Name="C组"/>
</Class>
</Grade>
<Grade Name="二年级">
<Class Name="甲班">
<Group Name="A组"/>
<Group Name="B组"/>
<Group Name="C组"/>
</Class>
<Class Name="乙班">
<Group Name="A组"/>
<Group Name="B组"/>
<Group Name="C组"/>
</Class>
</Grade>
<Grade Name="三年级">
<Class Name="甲班">
<Group Name="A组"/>
<Group Name="B组"/>
<Group Name="C组"/>
</Class>
<Class Name="乙班">
<Group Name="A组"/>
<Group Name="B组"/>
<Group Name="C组"/>
</Class>
</Grade>
</Data>
XAML

<Window x:Class="WpfControlTemlate.HierarchicalDataTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="HierarchicalDataTemplate" Height="300" Width="300">
<Window.Resources>
<XmlDataProvider x:Key="ds" Source="Data.xml" XPath="Data/Grade"/>
<!--ItemsSource="{Binding XPath=Class}"表示下一个节点的源-->
<HierarchicalDataTemplate DataType="Grade" ItemsSource="{Binding XPath=Class}">
<TextBlock Text="{Binding XPath=@Name}"/>
</HierarchicalDataTemplate> <HierarchicalDataTemplate DataType="Class" ItemsSource="{Binding XPath=Group}">
<RadioButton Content="{Binding XPath=@Name}" GroupName="gn"/>
</HierarchicalDataTemplate> <HierarchicalDataTemplate DataType="Group" >
<CheckBox Content="{Binding XPath=@Name}" />
</HierarchicalDataTemplate> </Window.Resources>
<Grid>
<TreeView Margin="5" ItemsSource="{Binding Source={StaticResource ds}}"/>
</Grid>
</Window>

效果如图9

图9

XML

<?xml version="1.0" encoding="utf-8" ?>
<Data xmlns="">
<Operation Name="文件" Gesture="F">
<Operation Name="新建" Gesture="N">
<Operation Name="项目" Gesture="Control+P"/>
<Operation Name="网站" Gesture="Control+W"/>
<Operation Name="文档" Gesture="Control+D"/>
</Operation>
<Operation Name="保存" Gesture="S"/>
<Operation Name="打印" Gesture="P"/>
<Operation Name="退出" Gesture="X"/>
</Operation>
<Operation Name="编辑" Gresture="E">
<Operation Name="拷贝" Gesture="Control+C"/>
<Operation Name="剪切" Gesture="Control+X"/>
<Operation Name="粘贴" Gesture="Control+V"/>
</Operation>
</Data>
XMAL

<Window x:Class="WpfControlTemlate.MenuTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MenuTemplate" Height="300" Width="300">
<Window.Resources>
<XmlDataProvider x:Key="ds" Source="MenuList.xml" XPath="Data/Operation"/> <HierarchicalDataTemplate DataType="Operation" ItemsSource="{Binding XPath=Operation}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding XPath=@Name}" Margin="10,0"/>
<TextBlock Text="{Binding XPath=@Gesture}"/>
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<StackPanel MenuItem.Click="StackPanel_Click">
<Menu ItemsSource="{Binding Source={StaticResource ds}}"/>
</StackPanel>
</Window>

后台代码是添加了单击事件来获取点击的是哪个菜单选项,我们可以根据其选项作出相应的操作。

CS

        private void StackPanel_Click(object sender, RoutedEventArgs e)
{
MenuItem mi = e.OriginalSource as MenuItem;
XmlElement xe = mi.Header as XmlElement;
MessageBox.Show(xe.Attributes["Name"].Value);
}

效果如图10

图10

五、Style

5.1Style的Setter

  前面已经稍微理解了一下Style的概念,下面就来记录一下其用法,Setter是设置器的意思。Style有个Setters标签,里面的值为Setter集合。对应的格式为<Setter Property="属性值" Value=“对应的属性值”/>下面来看个例子:

图11

其中上面的Setters标签可以省略。通过Style来限制TextBox的格式,如果不想使用的话,可以使用Style=“{x:Null}”。当然Style也可以添加在App.xaml文件中。如果想用style的话可以用<TextBox Text="Hello Style" Style="{DynamicResource textBoxStyle}"/>动态资源来套用。

5.2  Style中的基本Trigger

  Trigger,触发器,当某些条件满足的时间会触发一个行为。下面先介绍一下基本trigger。Trigger中也有Property和Value,用来限制条件,除此之外还有Setters,表示满足条件呈现的样式。下面的图为当CheckBox选中是字体呈现Orange颜色和20号字体。

图12

5.3 Style中的MultiTrigger

  这个触发器不能从名字上面理解,该触发器应该是多条件触发器,是属性满足了条件呈现特点的Style。下面例子为CheckBox选中,且Content为123的显示一定的Style。

图13

5.4由数据触发的DataTrigger

  在程序设计中,经常碰到如果客户输入不合法的字符串,要显示文本框为红色,来提醒客户。下面就演示一下具体怎么用:下面的例子为TextBox中的Text长度小于7会让Border保持红色。

XAML

<Window x:Class="Style.DataTriggerOfStyle"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Style"
Title="DataTriggerOfStyle" Height="300" Width="300">
<Window.Resources>
<local:LongToBoolConverter x:Key="LongToBool"/>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={x:Static RelativeSource.Self},Path=Text.Length,Converter={StaticResource LongToBool}}" Value="false">
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="1"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<TextBox Margin="5"/>
<TextBox Margin="5"/>
<TextBox Margin="5"/>
</StackPanel>
</Window>
public class LongToBoolConverter : IValueConverter
{
#region IValueConverter 成员 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int textLength = (int)value;
return textLength>?true:false;
} public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
} #endregion
}

效果为图14:

图14

  上面的代码中有个的地方是需要解释一下,绑定中有个的RelativeSource,RelativeSource 通过指定绑定源相对于绑定目标的位置,获取或设置绑定源。上面的意思其实就是绑定源的本身。上面还有个Converter,参数中的value已经是长度了,所以不需要直接转化为int型就可以了。

5.5多数据条件触发的MultiDataTrigger

  和上面的MultiTrigger相比,MultiDataTrigger主要验证数据,MultiTrigger验证属性。

XAML

<Window x:Class="Style.MultiDataTriggerOfStyle"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MultiDataTriggerOfStyle" Height="300" Width="300">
<Window.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ID}" Width="60"/>
<TextBlock Text="{Binding Name}" Width="120"/>
<TextBlock Text="{Binding Age}" Width="60"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=ID}" Value="2"/>
<Condition Binding="{Binding Path=Name}" Value="Tom"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Background" Value="Orange"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<ListBox x:Name="listBoxStudent" Margin="5"/>
</StackPanel>
</Window>
cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes; namespace Style
{
/// <summary>
/// MultiDataTriggerOfStyle.xaml 的交互逻辑
/// </summary>
public partial class MultiDataTriggerOfStyle : Window
{
public MultiDataTriggerOfStyle()
{
InitializeComponent();
this.listBoxStudent.ItemsSource = new List<Student> { new Student { ID = 1, Name = "Tim", Age = 30 }
, new Student { ID = 2, Name = "Tom", Age = 30 }
, new Student { ID = 3, Name = "lzp", Age = 30 }
, new Student { ID = 4, Name = "haiziguo", Age = 30 }};
}
}
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
}

效果如图15:

图15

5.6事件触发的EventTrigger

  该触发器与其他触发器不大一样,他不是属性也不是数据触发Style改变的,而是由事件触发的;被触发后不是执行的Setter,而是执行的一段动画。关于动画不做说明,下面只给出实例。记录完动画的章节,再回来看看。下面的例子是鼠标移到Button控件和离开执行的动画。

XAML

<Window x:Class="Style.EventTriggerOfStyle"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="EventTriggerOfStyle" Height="300" Width="300">
<Window.Resources>
<Style TargetType="Button">
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="150" Duration="0:0:0:2" Storyboard.TargetProperty="Width"/>
<DoubleAnimation To="150" Duration="0:0:0:2" Storyboard.TargetProperty="Height"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0:2" Storyboard.TargetProperty="Width"/>
<DoubleAnimation Duration="0:0:0:2" Storyboard.TargetProperty="Height"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded"/>
</Window.Triggers>
<Canvas>
<Button Width="40" Height="40" Content="OK"/>
</Canvas>
</Window>

六、总结

  本篇记录主要从DataTemplate和ControlTemplate入手,通过一些小例子来说明了他们的用途。注意区分其使用场合,前者只要是控制数据的显示方式,后者是控制控件的已有形状的改变。除此之外,还介绍了Style,由于其概念简单性,没有做过多的解释,只是给出了几个例子,等用到的时间再进行查阅。不足的地方是:关于ContentPresenter与DataTemplate以及ControlTemplate之间的关系不是太理解,所以本文少了一部分《寻找失落的控件》,如果有比较好的文章或者是比较好的资料帮助理解的,请留言,将不胜感激!本文是读书笔记,里面难免有理解不对的地方,欢迎讨论!最后祝大家节日愉快!下一篇:《深入浅出WPF》笔记——绘图与动画 。

《深入浅出WPF》笔记——模板篇的更多相关文章

  1. C# Note1:深入浅出WPF-MVVM篇

    一.资源说明 (1)配套视频:深入浅出WPF  讲的不错! 待更!

  2. 深入浅出WPF笔记

    数据层(Database,Oracle等) 业务逻辑层(Service,Data Access Layer,WCF) 表示层(WPF,Win Form,ASP.net,Silverlight) [WP ...

  3. 《深入浅出WPF》笔记——资源篇

    原文:<深入浅出WPF>笔记--资源篇 前面的记录有的地方已经用到了资源,本文就来详细的记录一下WPF中的资源.我们平时的“资源”一词是指“资财之源”,是创造人类社会财富的源泉.在计算机程 ...

  4. 《深入浅出WPF》笔记——事件篇

    如果对事件一点都不了解或者是模棱两可的话,建议先去看张子阳的委托与事件的文章(比较长,或许看完了,也忘记看这一篇了,没事,我会原谅你的)http://www.cnblogs.com/JimmyZhan ...

  5. 《深入浅出WPF》笔记——绘画与动画

    <深入浅出WPF>笔记——绘画与动画   本篇将记录一下如何在WPF中绘画和设计动画,这方面一直都不是VS的强项,然而它有一套利器Blend:这方面也不是我的优势,幸好我有博客园,能记录一 ...

  6. 《深入浅出WPF》 学习笔记

    <深入浅出WPF> 序言 1. 什么是WPF    2. 为什么要学习WPF 第一章 XAML概览 1. XAML是什么? 2. XAML有哪些优点 第二章 从零起步认识XAML 1. 新 ...

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

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

  8. 10-C++远征之模板篇-学习笔记

    C++远征之模板篇 将会学到的内容: 模板函数 & 模板类 -> 标准模板类 友元函数 & 友元类 静态数据成员 & 静态成员函数 运算符重载: 一切皆有可能 友元函数 ...

  9. 【【分享】深入浅出WPF全系列教程及源码 】

    因为原书作者的一再要求,在此声明,本书中的部分内容引用了原书名为<深入浅出WPF>的部分内容,假设博文不能满足你现有的学习须要,能够购买正版图书! 本人10月份提出离职,可是交接非常慢,预 ...

随机推荐

  1. BP神经网络公式推导及实现(MNIST)

    BP神经网络的基础介绍见:http://blog.csdn.net/fengbingchun/article/details/50274471,这里主要以公式推导为主. BP神经网络又称为误差反向传播 ...

  2. js进阶 12 jquery事件汇总

    js进阶 12 jquery事件汇总 一.常用事件 页面载入事件 ready() 文档就绪事件(当 HTML 文档就绪可用时) 鼠标事件 click() 触发.或将函数绑定到指定元素的 click 事 ...

  3. Topological Spaces(拓扑空间)

    拓扑空间的定义有多种形式,通过 open sets(开集)的形式定义是最为常见的拓扑空间定义形式. 1. 通过开集(open sets)定义 拓扑空间由一个有序对 (X,τ) 表示,X 表示非空集合, ...

  4. 任哲<<μC/OS>>

    从第二章开始啦: 程序控制块(TCB)  重要概念  相当于对应程序块的学生证,学号,,, 上面的图是一个简单的程序控制块,还会有复杂的程序控制块,也许是嵌套的两级的: 链表就相当于老师手中的花名册, ...

  5. linux 安装完mysql 密码重置

    If you have forgot the MySQL root password, can’t remember or want to break in….. you can reset them ...

  6. [Node.js] Testing ES6 Promises in Node.js using Mocha and Chai

    Writing great ES6 style Promises for Node.js is only half the battle. Your great modules must includ ...

  7. 【u125】最大子树和

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 小明对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题.一天他早晨骑车去上课 ...

  8. python 如何使用pip安装第三方软件

    1. 先将sripts加入系统的环境变量path中.如笔者的路径为: D:\Program Files\Python35\Scripts 2. 启动cmd,如安装request 过程十分简单,但是也容 ...

  9. ios开发事件处理之:一:UIView的拖拽

    1.ios当中常⽤的事件?  触摸事件 ,加速计事件 ,远程控制事件 2.什么是响应者对象? 继承了UIResponds的对象我们称它为响应者对象 UIApplication.UIViewContro ...

  10. Redis使用文档一

    1 Redis概述 1.1前言 Redis是一个开源.支持网络.基于内存亦可持久化的日志型.键值对存储数据库.使用ANSI C编写.并提供多种语言的API. 其开发由VMware主持,是最流行的键值对 ...