首页 > 其他分享 >WPF 模板

WPF 模板

时间:2024-08-27 10:28:25浏览次数:6  
标签:控件 容器 子项 get WPF public 模板

一、数据模板
继承了ItemConrol的控件对象(如ListView、ListBox、DataGrid、TabControl等等),都可以使用数据模板DataTemplate。

数据模板的作用在于决定每个Item中的数据的展示形式。

普通控件通过Template属性来定义模板,而子项容器控件则通过ItemTemplate属性来定义子项模板。

先创建作为数据源对象的类

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public int Gender { get; set; }
    public double Left { get; set; }
    public double Top { get; set; }
}

在xaml中定义数据集合,然后在子项容器控件中通过ItemTemplate属性定义子项数据模板。

<Window ......
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WPFStudy"
                ......>
    <Window.Resources>
        <!--数据集合-->
        <x:Array Type="local:Person" x:Key="persons">
            <local:Person Name="Hello" Age="20" Gender="1" Left="10" Top="50"/>
            <local:Person Name="Schuyler" Age="21" Gender="2"/>
            <local:Person Name="Cai" Age="22" Gender="1" Left="100" Top="250"/>
        </x:Array>  
    </Window.Resources>
    <Grid>
        <ItemsControl ItemsSource="{StaticResource persons}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="{Binding Name}"/>
                        <TextBlock Text="{Binding Age}" Grid.Column="1"/>
                        <TextBlock Text="{Binding Gender}" Grid.Column="2"/>
                        <TextBlock Text="{Binding Left}" Grid.Column="3"/>
                        <TextBlock Text="{Binding Top}" Grid.Column="4"/>
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>

二、子项容器模板

数据模板决定了数据的展示形式,而子项容器模板则决定了数据模板的展示形式。

子项容器模板可以通过子项容器控件的ItemsPanel进行设置。

<Window.Resources>
    <!--数据集合-->
    <x:Array Type="local:Person" x:Key="persons">
        <local:Person Name="Hello" Age="20" Gender="1" Left="10" Top="50"/>
        <local:Person Name="Schuyler" Age="21" Gender="2"/>
        <local:Person Name="Cai" Age="22" Gender="1" Left="100" Top="250"/>
    </x:Array>  
</Window.Resources>

<Grid>
    <ItemsControl ItemsSource="{StaticResource persons}">
                <!--这里是子项容器模板-->
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
                <!--这里是数据模板-->
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid Canvas.Top="{Binding Top}" Canvas.Left="{Binding Left}">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding Name}"/>
                    <TextBlock Text="{Binding Age}" Grid.Column="1"/>
                    <TextBlock Text="{Binding Gender}" Grid.Column="2"/>
                    <TextBlock Text="{Binding Left}" Grid.Column="3"/>
                    <TextBlock Text="{Binding Top}" Grid.Column="4"/>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

数据模板决定了每个Item中的数据怎么展示出来,而子项容器模板则决定了每个Item怎么展示出来。

如上述代码所示,会将ItemsControl的每个Item按序放入到Canvas中,由于Canvas的每个子元素都以左上角为原始坐标,所以堆在左上角了。

需要注意的是,在上述代码中数据模板的Grid设置了Canvas.Top和Canvas.Left属性值,但却没有效果,这是因为这两个属性只针对Canvas的直接子元素起作用。
然而ItemControl的数据模板中的容器对象(这里是Grid)并不是直接放置到子项容器模板的容器对象(这里是Canvas)中的,而是先将Grid放入到ContentPresenter元素后,
再将ContentPresenter元素放置到Canvas中。 因此正确的做法应该是在ItemsControl的ItemContainerStyle属性中对ContentPresenter进行样式设置。
<Grid>
    <ItemsControl ItemsSource="{StaticResource persons}">
                <!--应该在这里编写子项容器样式-->
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Top" Value="{Binding Top}"/>
                <Setter Property="Canvas.Left" Value="{Binding Left}"/>
            </Style>
        </ItemsControl.ItemContainerStyle>
        ......
    </ItemsControl>
</Grid>

完整的渲染过程(ItemsControl中的ItemsPresenter与ContentPresenter)
为了便于理解,这里简单描述一下ItemsControl的渲染过程,顺便缕一缕ItemsPresenter与ContentPresenter在ItemsControl控件中的作用

ItemsControl在渲染时,使用一个名为 ItemsPresenter 的控件来展示各个子项,主要用来控制如何布局(使用ItemsPanelTemplate中设定的容器)和显示这些子项,但它不是用于承载单个子项内容的控件。
ItemsControl在渲染时,会使用ContentPresenter控件来展示单个子项内容,并且ContentPresenter会放置子项容器中(使用ItemsPanelTemplate中设定的容器)

注意,并不是所有控件都是将子项放入ContentPresenter元素中的,例如ListView就是将子项放入ListViewItem中再放入子项容器模板的容器对象中的,ComboBox则是放入到ComboBoxItem中然后再放入到容器对象中的,在使用时可以配合snoop软件进行查看。

三、层级数据模板
继承了ItemsControl的控件,除了可以使用上面说的DataTemplate数据模板外,还可以使用继承DataTemplate的层级数据模板HeaderedItemsControl,该模板对象一般用于TreeView和Menu等具有层级关系的子项容器控件中。TreeView和Menu控件都是通过ItemTemplate属性来定义层级数据模板。

public class Menu
{
    public string Header { get; set; }
    public int Index { get; set; }
    public ObservableCollection<Menu> Children { get; set; }
}
public class MainWindowViewModel
{
    public ObservableCollection<Menu> Menus { get; set; }

    public MainWindowViewModel()
    {
        Menus = new ObservableCollection<Menu> { 
            new Menu
            {
                Header = "系统配置",
                Index = 0,
                Children = new ObservableCollection<Menu>{ 
                    new Menu{Header="用户设置", Index=0},
                    new Menu{Header="权限设置", Index=1}
                }
            },
            new Menu
            {
                Header = "样式配置",
                Index=1,
                Children = new ObservableCollection<Menu>{
                    new Menu{Header="主题", Index=0},
                    new Menu{Header="图片", Index=1}
                }
            }
        };
    }
}
<Window ......>
    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
        <TreeView ItemsSource="{Binding Menus}">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="{Binding Index}"/>
                        <TextBlock Text="{Binding Header}" Grid.Column="1"/>
                    </Grid>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</Window>

四、资源中的数据模板与容器模板
上面的例子中是将数据模板与子项容器模板直接使用在控件中,通过子项容器控件(继承了ItemControl的控件)的ItemTemplate和ItemsPanel属性来进行设置的(内联的用法),样式则是通过子项容器控件的ItemContainerStyle属性来设置。而数据模板、容器模板、子项容器样式的内容与控件模板的内容一样,都可以放置在<Window.Resources>作为资源来使用。

因此,上面的例子可以写成下面的形式:

<Window.Resources>
    <!--数据集合-->
    <x:Array Type="local:Person" x:Key="persons">
        <local:Person Name="Hello" Age="20" Gender="1" Left="10" Top="50"/>
        <local:Person Name="Schuyler" Age="21" Gender="2"/>
        <local:Person Name="Cai" Age="22" Gender="1" Left="100" Top="250"/>
    </x:Array>
        <!--数据模板-->
    <DataTemplate x:Key="dateTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding Name}"/>
            <TextBlock Text="{Binding Age}" Grid.Column="1"/>
            <TextBlock Text="{Binding Gender}" Grid.Column="2"/>
            <TextBlock Text="{Binding Left}" Grid.Column="3"/>
            <TextBlock Text="{Binding Top}" Grid.Column="4"/>
        </Grid>
    </DataTemplate>
        <!--子项容器模板-->
    <ItemsPanelTemplate x:Key="itemsPanelTemplate">
        <Canvas/>
    </ItemsPanelTemplate>
        <!--子项容器样式-->
    <Style x:Key="itemContainerStyle" TargetType="ContentPresenter">
        <Setter Property="Canvas.Top" Value="{Binding Top}"/>
        <Setter Property="Canvas.Left" Value="{Binding Left}"/>
    </Style>
</Window.Resources>
<Grid>
    <ItemsControl ItemsSource="{StaticResource persons}" 
                  ItemTemplate="{StaticResource dateTemplate}" 
                  ItemContainerStyle="{StaticResource itemContainerStyle}"
                  ItemsPanel="{StaticResource itemsPanelTemplate}">
    </ItemsControl>
</Grid>

模板选择器
考虑这么一个场景,子项容器控件中,子项源为Person的数组,每个Person对象中都有年龄Age属性,现在需要在大于20岁时,使用模板A;小于等于20岁时使用模板B。这样的需求显然只靠xaml代码是难以实现的,此时可以配合C#代码,定义一个模板选择器类型,根据不同的条件返回不同的模板对象。

使用模板选择器具体有如下几个步骤

1、定义模板资源

<Window.Resources>
    <!--数据集合-->
    <x:Array Type="local:Person" x:Key="persons">
        <local:Person Name="Hello" Age="20" Gender="1" Left="10" Top="50"/>
        <local:Person Name="Schuyler" Age="21" Gender="2"/>
        <local:Person Name="Cai" Age="22" Gender="1" Left="100" Top="250"/>
    </x:Array>
    <DataTemplate x:Key="dataTemplateA">
        <Grid>
            <TextBlock Text="{Binding Name}"/>
        </Grid>
    </DataTemplate>
    <DataTemplate x:Key="dataTemplateB">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding Name}"/>
            <TextBlock Text="{Binding Age}" Grid.Column="1"/>
        </Grid>
    </DataTemplate>
</Window.Resources>

2、创建模板选择器类型

可以通过查看ItemControl控件的ItemTemplateSelector属性的定义代码,得知其类型为DataTemplateSelector,因此可以创建一个MyDataTemplateSelector类型,继承DataTemplateSelector类,并重写其SelectTemplate函数。

DataTemplate SelectTemplate(object item, DependencyObject container):此函数会接收两个参数,item参数为子项的数据对象,本例中为Person对象;container参数则为子项所在的父类容器对象。

public class MyDataTemplateSelector: DataTemplateSelector
{
    //模板A,可以在xaml中赋值
    public DataTemplate TemplateA { get; set; }
    //模板B,可以在xaml中赋值
    public DataTemplate TemplateB { get; set; }
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var person = item as Person;
        if (person != null && person.Age > 20)
        {
            return TemplateA;
        }
        return TemplateB;
    }
}

3、在控件中使用模板选择器

<Window ......>
        ......
        <Grid>
        <ItemsControl ItemsSource="{StaticResource persons}">
            <ItemsControl.ItemTemplateSelector>
                <local:MyDataTemplateSelector 
                    TemplateA="{StaticResource dataTemplateA}"
                    TemplateB="{StaticResource dataTemplateB}"
                />
            </ItemsControl.ItemTemplateSelector>
        </ItemsControl>
    </Grid>
</Window>

子项容器控件中除了数据模板选择器ItemTemplateSelector外,还有子项容器模板选择器ItemContainerStyleSelector。

其他控件也有自己的模板选择器,比如继承了ContenteControl的控件(例如Button)都会有ContentTemplateSelector模板选择器。
来源:https://blog.csdn.net/jjailsa/article/details/135345658

 

标签:控件,容器,子项,get,WPF,public,模板
From: https://www.cnblogs.com/ywtssydm/p/18362936

相关文章

  • AE全套视频课程(视频+模板+练习文件)零基础必看
    视频课程超全练习文件模板完整版下载链接夸克:https://pan.quark.cn/s/54a848eb52e2如果夸克容量不足,可以参考这篇文章免费扩容 夸克网盘免费扩容......
  • 苹果cms影视海螺模板V4.0优化版整站源码
    苹果cms影视海螺模板V4.0优化版整站源码苹果CMS是一款流行的影视网站管理系统,它允许用户轻松地创建和管理自己的影视内容网站。影视海螺模板V4.0优化版是针对苹果CMS设计的一个模板,它提供了更加美观和功能丰富的界面,以及一些性能和用户体验上的优化。以下是关于苹果CMS影视海......
  • 【生日视频制作】广州塔表白字幕生日视频制作AE模板修改文字软件生成器教程特效素材【
    广州塔表白字幕生日视频制作教程AE模板改文字生成神器素材祝福怎么如何做的【生日视频制作】广州塔表白字幕生日视频制作AE模板修改文字软件生成器教程特效素材【AE模板】生日视频制作步骤:安装AE软件下载AE模板把AE模板导入AE软件修改图片或文字渲染出视频......
  • 【生日视频制作】一群美女挥手拉蓝横幅条幅AE模板修改文字软件生成器教程特效素材【AE
    一群美女挥手拉蓝条横幅生日视频制作教程AE模板修改文字生成器怎么如何做的【生日视频制作】一群美女挥手拉蓝横幅条幅AE模板修改文字软件生成器教程特效素材【AE模板】生日视频制作步骤:安装AE软件下载AE模板把AE模板导入AE软件修改图片或文字渲染出视频......
  • 海螺影视主题模板M3.1全解密版本 多功能苹果CMSv10自适应主题
    海螺影视主题模板M3.1全解密版本 多功能苹果CMSv10自适应主题海螺影视主题模板M3.1全解密版本多功能苹果CMSv10自适应主题源码介绍海螺影视主题模板M3.1是一款专为苹果CMSv10设计的自适应主题模板。该模板旨在提供一个美观、易用且功能丰富的界面,以满足影视网站的需求。模......
  • A2034热门电影视频网站模版源码 仿爱美剧网站模板源码 自适应手机端 内含 视频 资讯
    A2034热门电影视频网站模版源码 仿爱美剧网站模板源码 自适应手机端 内含 视频 资讯 留言热门电影视频网站模版源码-A2034源码介绍A2034是一款仿爱美剧网站模板的热门电影视频网站模版源码。该模版设计精美,功能齐全,支持自适应手机端浏览,为用户提供优质的视频观看体......
  • WPF中如何根据数据类型使用不同的数据模板
    我们在将一个数据集合绑定到列表控件时,有时候想根据不同的数据类型,显示为不同的效果。例如将一个文件夹集合绑定到ListBox时,系统文件夹显示为不同的效果,就可以使用模板选择器功能。WPF提供了一个模板选择器类型DataTemplateSelector,它可以根据数据对象和数据绑定元素来选择 Dat......
  • WPF 路由事件
    一、什么是路由事件?根据MSDN定义:功能定义:路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件。实现定义:路由事件是由类的实例支持的CLR事件,RoutedEvent由事件WindowsPresentationFoundation(WPF)系统处理。典型的WPF应......
  • 【生日视频制作】航拍哈尔滨超大堆雪人AE模板修改文字软件生成器教程特效素材【AE模板
    哈尔滨超大堆雪人生日视频制作教程AE模板修改文字软件生神器素怎么如何做的【生日视频制作】航拍哈尔滨超大堆雪人AE模板修改文字软件生成器教程特效素材【AE模板】生日视频制作步骤:安装AE软件下载AE模板把AE模板导入AE软件修改图片或文字渲染出视频......
  • 新建一个基于标准新建一个基于标准固件库的工程模板固件库的工程模板(实现LED单灯闪烁)
    实验报告原件在资源可选择性下载一、实验目的:1.了解STM32固件库;2.掌握STM32固件库关键子目录及固件库关键文件;3.能够新建一个基于标准固件库的工程模板并完成编译二、实验器材:笔记本或电脑。三、实验内容:1.构建proteus8LED构图。2.STM32构建适应于keil5的编译器格式......