• 【概念】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
    就是每个项的样式,自己重写,就可以定制出每个项的样式了。




    /*******相与枕藉乎舟中,不知东方之既白*******/
  • 相关阅读:
    mybatis mapper配置
    python 练习题
    python 函数
    python 文件处理
    python3 编码解码
    messagebox
    Python 基础
    PyMongo
    tkinter Text
    python tkinter entry
  • 原文地址:https://www.cnblogs.com/Mars-0603/p/14379087.html
Copyright © 2020-2023  润新知