【概念】WPF中的各种Template的区分(ControlTemplate、DataTemplate、HierarchicalDataTemplate)

入门学习:

https://www.cnblogs.com/huangxincheng/archive/2012/06/28/2566595.html

一、控件模板 ControlTemplate

利用ControlTemplate可以彻底的颠覆控件的默认外观。<ControlTemplate>里面的内容就是视觉树VisualTree。
两个重要属性:

(1)ContentPresenter

重定义控件模板,默认模板将会被覆盖,此时需要利用ContentPresenter,把原有模板的属性原封不动的投放到自定义模板中。

(2)Triggers

触发器列表,里面包含一些触发器Trigger,我们可以定制这个触发器列表来使控件对外界的刺激发生反应,比如鼠标经过时文本变成粗体等。

看例子:

<Window x:Class="WpfApplication1.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:sys="clr-namespace:System;assembly=mscorlib"
         Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ControlTemplate x:Key="rect" TargetType="{x:Type CheckBox}">
            <ControlTemplate.Resources>
                <SolidColorBrush x:Key="redBrush" Color="Red"/>
            </ControlTemplate.Resources>
            <StackPanel>
                <Rectangle Name="breakRectangle" Stroke="Red" StrokeThickness="2" Width="20" Height="20">
                    <Rectangle.Fill>
                        <SolidColorBrush Color="White"/>
                    </Rectangle.Fill>
                </Rectangle>
                <ContentPresenter/>
            </StackPanel>
            <ControlTemplate.Triggers>
                <Trigger Property="IsChecked" Value="True">
                    <Setter TargetName="breakRectangle" Property="Fill" Value="{StaticResource ResourceKey=redBrush}">
                    </Setter>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Window.Resources>
    <Canvas>
        <CheckBox Template="{StaticResource ResourceKey=rect}"  Content="我是CheckBox"/>
    </Canvas>
</Window>
<ContentPresenter Margin="{TemplateBinding Padding}" /> 实现了将模板中的Margin绑定到原控件中的Padding上去。

写到Style里就是:
        <Style x:Key="cbx" TargetType="{x:Type CheckBox}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type CheckBox}">
                        <ControlTemplate.Resources>
                            <SolidColorBrush x:Key="redBrush" Color="Red"/>
                        </ControlTemplate.Resources>
                        <StackPanel>
                            <Rectangle Name="breakRectangle" Stroke="Red" StrokeThickness="2" Width="20" Height="20">
                                <Rectangle.Fill>
                                    <SolidColorBrush Color="White"/>
                                </Rectangle.Fill>
                            </Rectangle>
                            <ContentPresenter/>
                        </StackPanel>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="True">
                                <Setter TargetName="breakRectangle" Property="Fill" Value="{StaticResource ResourceKey=redBrush}">
                                </Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

调用:

<CheckBox Style="{StaticResource ResourceKey=cbx}" Content="我是CheckBox"/>

 

(3)ItemsPresenter

继承自ItemsControl的控件,有一个ItemsPanel属性作为集合元素承载容器。子元素ItemsPresenter负责呈现控件的任务。

只要把ItemsPresenter放在内部模板中,那么ItemsPresenter则会去检测父元素是否为集合控件,然后将ItemsPanel添加到其内部视觉树当中。

<Style x:Key="{x:Type ItemsControl}"
           TargetType="{x:Type ItemsControl}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ItemsControl}">
                        <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Padding="{TemplateBinding Padding}"
                            SnapsToDevicePixels="true">
                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

比较常见的继承自ItemsControl的控件,比如ComboBox,ContextMenu,ListBox,DataGrid,ListView等。

 

二、数据模板 DataTemplate

数据模板定义了数据的显示方式,也就是数据对象的可视结构。主要是可以自定义控件的同时进行数据绑定。

<Window x:Class="WpfApplication1.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:src="clr-namespace:WpfApplication1"
         Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ObjectDataProvider x:Key="personList" ObjectType="{x:Type src:PersonList}"/>
        <DataTemplate x:Key="rect">
            <Border Name="border" BorderBrush="Aqua" BorderThickness="1" Padding="5" Margin="5">
                <StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}" Margin="5,0,0,0"/>
                        <TextBlock Text="{Binding Age}" Margin="5,0,0,0"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Address}" Margin="5,0,0,0"/>
                    </StackPanel>
                </StackPanel>
            </Border>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding Source={StaticResource ResourceKey=personList}}"
                  ItemTemplate="{StaticResource ResourceKey=rect}"></ListBox>
    </Grid>
</Window>

 

注意这里在调用时应该绑定的是 ItemTemplate 属性。

1、一些例子

数据模板作用于

(1)ContentControl控件(内容控件)

(有Content属性的控件是ContentControl控件)

被ContentControl控件的ContentTemplate属性使用。

最常用的ContentControl控件包括:Button、ButtonBase、CheckBox、ComboBoxItem、Label、ListBoxItem、ListViewItem、RadioButton、ToolTip、UserControl、Window等。

 

一个运用数据模板的Button实例:https://blog.csdn.net/u014650759/article/details/98472155

数据模板通过Content属性指定数据源,将数据先绑定到Content属性上,再通过ContentTemplate指定数据处理方式。

 

(2)ItemsControl控件(项控件)

被ItemsControl控件的ItemTemplate属性。

最常见的ItemsControl控件包括:Menu、MenuBase、ContextMenu、ComoBox、ListBox、ListView等。

 

一个运用数据模板的ListBox实例:https://blog.csdn.net/yl2isoft/article/details/38712449

DataTemplate数据绑定是怎样实现的?

ListBox包含属性ItemTemplate。将ItemTemplate属性绑定到自定义的DataTemplate,ListBox则按照对象个数创建多个ListBoxItem,并将ListBoxItem的DataContext设置为相应的Student对象,同时将DataTemplate中的元素绑定到Student对象的属性。

 

(3)被GridViewColumn控件的CellTemplate属性使用。

即用于设置控件的数据内容。

 

2、HierarchicalDataTemplate

它是针对具有分层数据结构的控件设计的,比如说TreeView,相当于可以每一个层级上做DataTemplate。

https://www.cnblogs.com/goldren/archive/2012/12/11/2812697.html

 

3、数据模板和控件模板的区别

(1)面对的绑定对象类型不一致。

ControlTemplate只是为了自己而呈现的,并不反映基础数据。

DataTemplate可以为用户呈现数据。

(2) 数据模板通常在页面xaml内部直接定义,而控件模板通常放到样式(Style)文件中。

 

4、展开说一下ContentControl与ContentPresenter

数据是如何显示出来的?虽然数据模板定义了数据的可视结构,但只有控件才是可视的,数据一般是被控件承载,这里需要另外的一个对象ContentPresenter。

内容控件的Content属性是由ContentControl类定义的,ContentPresenter负责将ContentControl的Content属性显示出来。

    <!--使用ContentPresenter对Button进行重绘-->
        <Style TargetType="Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <ContentPresenter/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!--使用TextBlock对Button进行重绘-->
    <Style TargetType="Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <TextBlock Text="{TemplateBinding Content}"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

可见使用ContentPresenter非常的方便,只要将ContentPresenter放在模板中即可,也不需要做任何的额外的绑定。

(ContentPresenter内部帮我们做了默认的绑定)。如果使用TextBlock还是需要做绑定的。

ContentPresenter默认呈现文字,但可以自己以Content为数据源而重新定义模板(ContentTemplate),则ContentPresenter将不再局限于文字的呈现。

如果只是为了呈现文字的话,是不需要ContentPresenter的。

        <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" Content="hello">
            <ContentPresenter.ContentTemplate>
                <DataTemplate>
                    <Border BorderBrush="Wheat">
                        <TextBlock Text="{Binding xxx}"/>
                    </Border>
                </DataTemplate>
            </ContentPresenter.ContentTemplate>
        </ContentPresenter>

不如说ContentControl是ContentPresenter的一个特例,而ContentPresenter则是ContentControl的基础。

为了适配ContentPresenter,ContentControl提供了内容模型的相关属性,本质上ContentPresenter并非仅仅只是用到ContentControl而已,ContentPresenter可以通过指定ContentSource来绑定指定的源属性。

 

三、ItemsPanelTemplate

首先我们要知道常见的条目控件有:ListBox,Menu,StatusBar等。

比如拿ListBox来说,ItemBox的ItemPanel其实是一个VisualizingStackPanel,就是说ListBox的每一项的排列方式是遵循StackPanel的

原则,也就是从上到下的排列方式。如果要实现从左到右排列:

<Window x:Class="WpfApplication1.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:src="clr-namespace:WpfApplication1"
         Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ObjectDataProvider x:Key="personList" ObjectType="{x:Type src:PersonList}"/>
        <DataTemplate x:Key="rect">
            <Border Name="border" BorderBrush="Aqua" BorderThickness="1" Padding="5" Margin="5">
                <StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}" Margin="5,0,0,0"/>
                        <TextBlock Text="{Binding Age}" Margin="5,0,0,0"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Address}" Margin="5,0,0,0"/>
                    </StackPanel>
                </StackPanel>
            </Border>
        </DataTemplate>
        <ItemsPanelTemplate x:Key="items">
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        </ItemsPanelTemplate>
    </Window.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding Source={StaticResource ResourceKey=personList}}"
                  ItemTemplate="{StaticResource ResourceKey=rect}" ItemsPanel="{StaticResource ResourceKey=items}"></ListBox>
    </Grid>
</Window>

也就是说,ItemsPanelTemplate可以用来定义集合控件的容器外观。

 

四、总结

1、Template
控件模板,是指整个控件的展示和布局。
如ComboBox,可分为文本区域,下拉按钮区域,Items的Popup区域。
Template就是管理这些位置的布局。


2、ItemsPresenter
可以简单理解为占位符,在样式中使用,标记着这个区域用来展示该控件的Items。
如:ComboBox的下拉列表的可选项。
但是,只负责显示,而不能管理如何显示,如果我们要内容横向排列,就要用到ItemsPanel。


3、ItemsPanel
管理Items的排列方式,如,ComboBox默认是竖直排列的,我们要横着排列,只需要定义ItemsPanel为WrapPanel,就可以了。
这时候Items的排列方式已经完成,如果还要让ComboBox的每个项都重写,比如,背景、图标等,就要用到ItemContainerStyle。

4、ItemContainerStyle
就是每个项的样式,自己重写,就可以定制出每个项的样式了。




posted @ 2021-02-05 17:48  不溯流光  阅读(3250)  评论(0编辑  收藏  举报