在WPF中有三大模板ControlTemplate,ItemsPanelTemplate,DataTemplate.其中ControlTemplate和ItemsPanelTemplate是控件模板,DataTemplate是数据模板,他们都派生自FrameworkTemplate抽象类。

1、ControlTemplate

ControlTemplate:控件模板主要有两个重要属性:VisualTree内容属性和Triggers触发器。所谓VisualTree(视觉树),就是呈现我们所画的控件。Triggers可以对我们的视觉树上的元素进行一些变化。一般用于单内容控件。

画一个按钮模板来举例说明:

<Style TargetType="Button">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid>
                            <Ellipse Width="100" Height="100">
                                <Ellipse.Fill>
                                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                        <GradientStop Offset="0" Color="blue"/>
                                        <GradientStop Offset="1" Color="LightBlue"/>
                                    </LinearGradientBrush>
                                </Ellipse.Fill>
                            </Ellipse>
                            <Ellipse Width="80" Height="80">
                                <Ellipse.Fill>
                                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                        <GradientStop Offset="0" Color="White"/>
                                        <GradientStop Offset="1" Color="Transparent"/>
                                    </LinearGradientBrush>
                                </Ellipse.Fill>
                            </Ellipse>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

<Button Content="Hello WPF"/>

结果:

ControlTemplate之子 ContentControl和ContentPresenter

我们在ControlTemplate中画了两个椭圆,应用于所有的Button按钮,但我们Button中有Content属性(内容为Hello WPF),却没有显示出来。因为这里用ControlTemplate重写了Button的样式,所以我们也要在ControlTemplate中增加ContentControl。通过ContentControl中的Content来绑定父容器的Content属性。

代码<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Width="100" Height="100">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="blue"/>
<GradientStop Offset="1" Color="LightBlue"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse Width="80" Height="80">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="White"/>
<GradientStop Offset="1" Color="Transparent"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<ContentControl VerticalAlignment="Center" HorizontalAlignment="Center" Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

这下内容出来了

我们来看一下,ContentControl继承于Control的,用MSDN的话是:表示包含单项内容的控件、ContentControl 可以包含任何类型的公共语言运行库对象。如下ContentControl类图。

为了提高性能,我们可以用一个ControlPresenter来代替ContentControl,效果还是一样,那他们有什么区别呢?

来看下ControlPresenter这个类,它继承于FreameworkElement,如下图:

ControlPresenter 通常叫做内容占位符。所以我们可以看到

<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/>来代替<ContentControl VerticalAlignment="Center" HorizontalAlignment="Center" Content="{TemplateBinding Content}"/> 。这里少了Content绑定父容器,因为ControlPresenter有个隐式的Content="{TemplateBinding Content}",也就是你可以写也可以不写它。

从他们的基类可以看出,ContentControl比ContentPresenter大多了。其实ControlPresenter是一个原始的构建块,而ContentControl是一个带控件模板的成熟控件(里面包含ControlPresenter)。

所以我们一般用ControlPresenter。

ControlTemplate的VisualTree我们讲过了,下面看下他的trigger如何运用。

我们在原来的代码中增加

<ControlTemplate.Triggers>
             <Trigger Property="IsMouseOver" Value="true">
                   <Setter TargetName="ellipse1" Property="Fill" Value="Red"/>
             </Trigger>
 </ControlTemplate.Triggers>

当我们把鼠标移上去的时候就会变成如下图所示:

发挥我们的想象力,我们可以根据ControlTemplate做更多的特效。如下

<Style TargetType="CheckBox">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="CheckBox">
                        <DockPanel>
                            <ContentPresenter DockPanel.Dock="Left" VerticalAlignment="Center" />
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="30"/>
                                    <ColumnDefinition Width="30"/>
                                </Grid.ColumnDefinitions>
                                <Rectangle Grid.Column="0" Grid.ColumnSpan="2" Fill="Gray"/>
                                <TextBlock x:Name="txtBox"  Foreground="White" />
                            </Grid>
                        </DockPanel>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="True">
                                <Setter TargetName="txtBox" Property="Grid.Column" Value="1"/>
                                <Setter TargetName="txtBox" Property="Text" Value="On"/>
                                <Setter TargetName="txtBox" Property="Background" Value="LightBlue"/>
                            </Trigger>
                            <Trigger Property="IsChecked" Value="{x:Null}">
                                <Setter TargetName="txtBox" Property="Grid.Column" Value="0"/>
                            </Trigger>
                            <Trigger Property="IsChecked" Value="false">
                                <Setter TargetName="txtBox" Property="Grid.Column" Value="0"/>
                                <Setter TargetName="txtBox" Property="Text" Value="OFF"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
<Grid>
        <CheckBox Width="100" Height="30" Content="Click Me"/>
 </Grid>

效果图:点击之前点击之后

2、ItemsPanelTemplate

ItemsPanelTemplate在MSDN的解释是:ItemsPanelTemplate 指定用于项的布局的面板。 GroupStyle 具有一个类型为 ItemsPanelTemplate 的 Panel 属性。 ItemsControl 类型具有一个类型为ItemsPanelTemplate 的 ItemsPanel 属性。

我们先讲ItemTemplate。它一般用在多个内容控件的模板。比如ListBox。

如下看ListBox应用ItemTemplate:

在xaml中

<Style TargetType="ListBox">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding UriSource}" Width="100" Height="100"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>

<ListBox x:Name="listBox" />

在后台代码我们给它一些图片来填充这个ListBox.

代码 public partial class ListBoxUserControl : UserControl
{
public ListBoxUserControl()
{
InitializeComponent();
listBox.ItemsSource = LoadImages();
} public List<BitmapImage> LoadImages()
{
List<BitmapImage> bitmapImages=new List<BitmapImage>();
DirectoryInfo directoryInfo = new DirectoryInfo(@"E:\WPFDEMO\ControlTest\ControlTest\Images");
foreach (var item in directoryInfo.GetFiles("*.jpg"))
{
Uri uri=new Uri(item.FullName);
bitmapImages.Add(new BitmapImage(uri));
}
return bitmapImages;
}
}

每一张图片就是一个Item。

我们如果想让图片以横向显示。一开始我以为用StackPanel的Orientation=”Horiziontal”,发现犯了个错误。这样设置是现在把Items中某一个item中的内容水平显示啊。这时就要用到ItemsPanelTemplate这个模板了。我们在ListBox的样式中增加如下红色区域的代码:

 <Style TargetType="ListBox">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding UriSource}" Width="100" Height="100"/>
<TextBlock Text="qq" Background="Red"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>

<Setter Property="ItemsPanel">                <Setter.Value>                    < ItemsPanelTemplate>                        <StackPanel />                    </ItemsPanelTemplate>                </Setter.Value>            </Setter>

        </Style>

这里我在DataTemplate中加了StackPanel 为了说明加在这里的效果只是区分:Items整体横向和Item中内容的区别。

现在我们要想让布局可以随着窗体宽度变化,我们只要把ItemsPanelTemplate中的StackPanel 改成WrapPanel,并且设置ListBox的ScrollViewer.HorizontalScrollBarVisibility="Disabled",这样才可以看到效果。

ControlTemplate之 ItemsPresenter和ContentPresenter

我们先构造一个TreeView

xaml中:

在开始加个Loaded="UserControl_Loaded"

<Grid>
        <TreeView x:Name="treeview" />
</Grid>

后台代码中:

代码  public class Node
{
private IList<Node> _childNodes;
private string _name;
public Node()
{}
public Node(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
set { _name = value; }
} public IList<Node> ChildNodes
{
get
{
if (_childNodes==null)
_childNodes=new List<Node>();
return _childNodes;
} }
} public partial class TreeViewUserControl : UserControl
{
public TreeViewUserControl()
{
InitializeComponent();
} private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
treeview.PreviewKeyDown += (o,a) => { a.Handled = true; };
PopulateTreeView();
}
void PopulateTreeView()
{
Node rootNode=new Node("GrandFather");
for (int i = 0; i < 2; i++)
{
Node child=new Node("Father");
rootNode.ChildNodes.Add(child);
for (int j = 0; j < 3; j++)
{
Node child2=new Node("Son");
child.ChildNodes.Add(child2);
}
} Node dummy=new Node();
dummy.ChildNodes.Add(rootNode);
treeview.ItemsSource = dummy.ChildNodes;
} }

没有任何样式的TreeView

下面我们如何运用ItemsPresenter和ContentPresenter来添加样式。来实现下面这幅图的效果

在TreeView中ItemsPresenter和ContentPresenter是什么关系:ContentPresenter是用来显示TreeView中Item的内容 。ItemsPresenter是用来显示它的子项(Item的子项,也就是说child’s Items)。

样式代码<Style TargetType="TreeViewItem">
<Style.Resources>
<LinearGradientBrush x:Key="ItemAreaBrush" StartPoint="0,0.5" EndPoint="0.5,1">
<GradientStop Offset="0" Color="#66000000"/>
<GradientStop Offset="1" Color="#22000000"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="SelectedItemAreaBrush" StartPoint="0.5, 0" EndPoint="0.5, 1">
<GradientStop Color="Orange" Offset="0" />
<GradientStop Color="OrangeRed" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="ItemBorderBrush" StartPoint="0.5, 0" EndPoint="0.5, 1">
<GradientStop Color="LightGray" Offset="0" />
<GradientStop Color="Gray" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="SelectedItemBorderBrush" StartPoint="0.5, 0" EndPoint="0.5, 1">
<GradientStop Color="Yellow" Offset="0" />
<GradientStop Color="Black" Offset="1" />
</LinearGradientBrush>
<DropShadowBitmapEffect x:Key="DropShadowEffect"/>
</Style.Resources>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem">
<Grid Margin="2">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border x:Name="border" Background="{StaticResource ResourceKey=ItemAreaBrush}"
BorderBrush="{StaticResource ItemBorderBrush}" BorderThickness="1" CornerRadius="8" Padding="6">
<ContentPresenter ContentSource="Header" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
<ItemsPresenter Grid.Row="1"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="border" Property="Panel.Background" Value="{StaticResource SelectedItemAreaBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" IsItemsHost="True"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter> </Style>

看红色代码的部分,这里ContentPresenter显示了父容器的Header的内容,比如GrandFather,Father,Son.而ItemsPresenter则是否让他显示其子元素。比如GrandFather的子元素为Father,没有设置<ItemsPresenter Grid.Row="1"/> 的话。子元素Father是不会显示的。

这里为了突出层次化,运用了ItemsPanelTemplate。最后我们在资源里引用这个样式。

代码<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Controls/TreeViewItemStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
<HierarchicalDataTemplate DataType="{x:Type controls:Node}" ItemsSource="{Binding ChildNodes}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</ResourceDictionary>
</UserControl.Resources>

3、DataTemplate和HierarchicalDataTemplate

DataTemplate就是显示绑定数据对象的模板。 HierarchicalDataTemplate继承于DataTemplate,它专门对TreeViewItemMenuItem的一些数据对象的绑定。

想了解下DataTemplate和HierarchicalDataTemplate,就看以上的例子吧。他们中只要有控件的绑定都会用到。想了解的更深一步,请看下南柯之石的这篇文章。

ControlTemplate,ItemsPanelTemplate,DataTemplate(wpf)的更多相关文章

  1. Style、ControlTemplate 和 DataTemplate 触发器

    本文摘要:    1:属性触发器:    2:数据触发器:    3:事件触发器: Style.ControlTemplate 和 DataTemplate 都有触发器集合.    属性触发器只检查W ...

  2. 背水一战 Windows 10 (76) - 控件(控件基类): Control - 基础知识, 焦点相关, 运行时获取 ControlTemplate 和 DataTemplate 中的元素

    [源码下载] 背水一战 Windows 10 (76) - 控件(控件基类): Control - 基础知识, 焦点相关, 运行时获取 ControlTemplate 和 DataTemplate 中 ...

  3. WPF的ControlTemplate和DataTemplate简介

    首先理清几个概念,Template.ControlTemplate.ContentTemplate.DataTemplate.ContentControl 这几个东西名字都差不多,意思感觉也接近,初次 ...

  4. WPF : ControlTemplate和DataTemplate的区别

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

  5. wpf中在style的template寻找ControlTemplate和DataTemplate的控件

    一.WPF中的两棵树 WPF中每个控件的Template都是由ControlTemplate构成,ControlTemplate包含了构成该控件的各种子控件,这些子控件就构成了VisualTree:而 ...

  6. WPF中ControlTemplate和DataTemplate的区别

    下面代码很好的解释了它们之间的区别: <Window x:Class="WPFTestMe.Window12" xmlns="http://schemas.micr ...

  7. WPF 详解模板

    在WPF中有三大模板 ControlTemplate,ItemsPanelTemplate,DataTemplate.其中ControlTemplate和 ItemsPanelTemplate是控件模 ...

  8. WPF模板(二)应用

    本次内容来源于电子书,和上一篇一样. 在WPF中有三大模板ControlTemplate,ItemsPanelTemplate,DataTemplate.其中ControlTemplate和Items ...

  9. Template简介

    分类   ControlTemplate ItemsPanelTemplate DataTemplate 样式Style和模板Template对比 Style:样式,风格Template:模版,某种控 ...

随机推荐

  1. What are DESC and ASC Keywords?

    What are DESC and ASC Keywords? ASC is the short form for ascending DESC is the short form for desce ...

  2. PAT 1070. 结绳(25)

    给定一段一段的绳子,你需要把它们串成一条绳.每次串连的时候,是把两段绳子对折,再如下图所示套接在一起.这样得到的绳子又被当成是另一段绳子,可以再次对折去跟另一段绳子串连.每次串连后,原来两段绳子的长度 ...

  3. time 和 datetime 模块

    在Python中,通常有这几种方式来表示时间: 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量.我们运行“type(time.time( ...

  4. 转载:Linux下查看/修改系统时区、时间

    一.查看和修改Linux的时区 1. 查看当前时区 命令 : "date -R" 2. 修改设置Linux服务器时区 方法 A 命令 : "tzselect" ...

  5. Node.js的概念与应用

    转:http://blog.jobbole.com/100058/?utm_source=blog.jobbole.com&utm_medium=relatedPosts Node.js 是什 ...

  6. ACM解题之(ZOJ 2724)Windows Message Queue

    题目来源: 点击打开链接 题目翻译: 消息队列是windows系统的基本基础.对于每个进程,系统都维护一个消息队列.如果这个过程发生某些事情,例如鼠标点击,文本改变,系统会向队列添加一条消息.同时,如 ...

  7. chrome浏览器插件让你浏览github的时候像IDE一样提供项目目录

    GitHub 作为代码托管平台,竟然没有提供项目目录,方便用户在线快速浏览项目结构.所以,在线分析项目源码就会变得很繁琐,必须一层一层点击,然后再一次一次地向上返回.要知道,本来 GitHub 网站在 ...

  8. Kattis - convexpolygonarea 【数学】

    题意 给出一系列点,求这个多边形面积 思路 向量叉积 AC代码 #include <cstdio> #include <cstring> #include <ctype. ...

  9. iOS Swift 熊猫🐼跑酷 第一个小项目

    前言:想用swift  写个小游戏 慢慢转化 能写出 ARKit来.但是又不能一口吃个胖子,慢慢来,在网络视频教程中撸了视频教学,断断续续看了半个多月,基本实现了 游戏主角

  10. MACHINE_START-内核板级初始化实现机制(linux3.1.0)

    转:https://blog.csdn.net/charliewangg12/article/details/41518549 在驱动开发时,我们都是以一块开发板为基础移植驱动程序.每一块开发板对应一 ...