wpf模板之DataTemplate

发布于:2025-09-04 ⋅ 阅读:(22) ⋅ 点赞:(0)

前言

DataTemplate也称为数据模板, 是 WPF 中一个极其强大和核心的概念,它的主要作用是定义数据对象在 UI 上的可视化呈现方式,比如一个 Person 类的对象,如果将这个对象赋值给ContentControl 的Content属性,则默认只会显示其 调用ToString() 方法返回的结果,这通常不是我们想要的,我们想要将其转换为用户能看到和理解的视觉元素(如文本框、图片等),比如Person类有姓名属性、年龄属性、邮箱属性,我们想将这三个属性分为三行显示就需要借助DataTemplate。

1、应用于ContentControl

1.1代码

下面的代码中DataTemplate位于 Window.Resources中,并且它的的DataType属性指定了数据模板作用的类,也就是Person类,然后最外层是一个Border边框,里面是一个StackPanel容器,容器中放了TextBlock、StackPanel 、TextBlock ,其中第一个TextBlock绑定了Person类的Name属性;StackPanel里面有两个TextBlock,分别绑定了"Age:"字符串和Person类的Age属性;最后一个TextBlock绑定了Person类的Email属性。
1)xaml代码

<Window x:Class="DataTemplate之ContentControl.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DataTemplate之ContentControl"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:Person}">
            <Border Background="#FFE3F2FD" CornerRadius="10" Padding="15"
                BorderBrush="#FF90CAF9" BorderThickness="2">
                <StackPanel>
                    <TextBlock Text="{Binding Name}" FontSize="18" FontWeight="Bold"/>
                    <StackPanel Orientation="Horizontal" Margin="0,5,0,0">
                        <TextBlock Text="Age: " FontWeight="SemiBold"/>
                        <TextBlock Text="{Binding Age}"/>
                    </StackPanel>
                    <TextBlock Text="{Binding Email}" TextDecorations="Underline" 
                           Foreground="Blue" Margin="0,5,0,0"/>
                </StackPanel>
            </Border>
        </DataTemplate>
    </Window.Resources>
    <StackPanel Orientation="Vertical">
        <Button Content="{Binding person}"  HorizontalAlignment="Center" VerticalAlignment="Center" />
        <Button Content="{Binding person}"   HorizontalAlignment="Center" VerticalAlignment="Center" />
        <Button Content="{Binding person}"  HorizontalAlignment="Center" VerticalAlignment="Center" />
    </StackPanel>
</Window>

2) ViewModelBase类

 public class ViewModelBase
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propname)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propname));
            }
        }
    }

3)ViewModel 类

 public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        Person _person;
        public  Person person
        {
            get
            {
                return _person;
            }
            set
            {
                _person = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("person"));
            }
        }

        public ViewModel()
        {
            person = new Person
            {
                Name = "张伟",
                Age = 28,
                Email = "zhangwei@example.com",
            };
        }
    }

4)MainWindow 类

 public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new ViewModel();
        }
    }

window窗体放了1个StackPanel 并指定其中的子元素按照垂直方向排列,StackPanel 中添加了三个Button,并且每个Button的Content属性都绑定了ViewModel类中的person属性。

1. 2运行结果

可以看到Person类的对象的三个属性分别变成了Button控件中的三行。
在这里插入图片描述

2、应用于ItemsControl

2.1 代码

下面的代码中对于资源文件指定了key等于PersonDataTemplate,然后在Button中为ContentTemplate绑定资源文件PersonDataTemplate,在ListBox中为ItemTemplate绑定资源文件PersonDataTemplate。
1)xaml代码

<Window x:Class="DataTemplate之ContentControl.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DataTemplate之ContentControl"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <DataTemplate x:Key="PersonDataTemplate" DataType="{x:Type local:Person}">
            <Border Background="#FFE3F2FD" CornerRadius="10" Padding="15"
                BorderBrush="#FF90CAF9" BorderThickness="2">
                <StackPanel>
                    <TextBlock Text="{Binding Name}" FontSize="18" FontWeight="Bold"/>
                    <StackPanel Orientation="Horizontal" Margin="0,5,0,0">
                        <TextBlock Text="Age: " FontWeight="SemiBold"/>
                        <TextBlock Text="{Binding Age}"/>
                    </StackPanel>
                    <TextBlock Text="{Binding Email}" TextDecorations="Underline" 
                           Foreground="Blue" Margin="0,5,0,0"/>
                </StackPanel>
            </Border>
        </DataTemplate>
    </Window.Resources>
    <StackPanel Orientation="Vertical">
        <Button ContentTemplate="{StaticResource PersonDataTemplate}" Content="{Binding person}"  HorizontalAlignment="Center" VerticalAlignment="Center" />
        <ListBox ItemsSource="{Binding PersonList}" ItemTemplate="{StaticResource PersonDataTemplate}" HorizontalAlignment="Center">
        </ListBox>
    </StackPanel>
</Window>

2) ViewModelBase类

 public class ViewModelBase
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propname)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propname));
            }
        }
    }

3)ViewModel 类

public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        Person _person;
        public  Person person
        {
            get
            {
                return _person;
            }
            set
            {
                _person = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("person"));
            }
        }

        public ViewModel()
        {
            person = new Person
            {
                Name = "张伟",
                Age = 28,
                Email = "zhangwei@example.com",
            };

            PersonList = new ObservableCollection<Person>();

            PersonList.Add(new Person
            {
                Name = "小李",
                Age = 20,
                Email = "xiaoli@example.com",
            });
            PersonList.Add(new Person
            {
                Name = "小王",
                Age = 25,
                Email = "xiaowang@example.com",
            });

        }

        private ObservableCollection<Person> _personList;
        public ObservableCollection<Person> PersonList
        {
            get
            {
                return _personList;
            }
            set
            {
                _personList = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("person"));
            }
        }
    }

4)MainWindow 类

 public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new ViewModel();
        }
    }

window窗体放了1个StackPanel 并指定其中的子元素按照垂直方向排列,StackPanel 中添加了1个Button和1个ListBox,并且Button的Content属性绑定了ViewModel类中的person属性,ListBox的ItemsSource属性绑定了ViewModel类中的PersonList属性。

2.2 运行结果

可以看到Person类的对象的三个属性分别变成了Button控件中的3行,以及ListBox中的每一项的3行。
在这里插入图片描述

3、应用于DataGrid

3.1 代码

下面的代码中对于资源文件指定了key等于PersonDataTemplate,然后在DataGrid中为CellTemplate绑定资源文件PersonDataTemplate,这里需要注意的是DataGrid是为列绑定模板而不是为DataGrid绑定模板,所以不同列可以绑定不同模板,并且AutoGenerateColumns要设置为false,否则就会根据绑定的数据内容自动生成列;CanUserAddRows也要设置为false。
1)xaml代码

<Window x:Class="DataTemplate之ContentControl.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DataTemplate之ContentControl"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <DataTemplate x:Key="PersonDataTemplate" DataType="{x:Type local:Person}">
            <Border Background="#FFE3F2FD" CornerRadius="10" Padding="15"
                BorderBrush="#FF90CAF9" BorderThickness="2">
                <StackPanel>
                    <TextBlock Text="{Binding Name}" FontSize="18" FontWeight="Bold"/>
                    <StackPanel Orientation="Horizontal" Margin="0,5,0,0">
                        <TextBlock Text="Age: " FontWeight="SemiBold"/>
                        <TextBlock Text="{Binding Age}"/>
                    </StackPanel>
                    <TextBlock Text="{Binding Email}" TextDecorations="Underline" 
                           Foreground="Blue" Margin="0,5,0,0"/>
                </StackPanel>
            </Border>
        </DataTemplate>
    </Window.Resources>
    <DataGrid  ItemsSource="{Binding PersonList}"   AutoGenerateColumns="False"   CanUserAddRows="False"    >
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="个人信息" CellTemplate="{StaticResource PersonDataTemplate}"/>
        </DataGrid.Columns>
    </DataGrid >
</Window>

32.2 运行结果

最终DataGrid会有一列,列名为“个人信息”。
在这里插入图片描述

马工撰写的年入30万+C#上位机项目实战必备教程(点击下方链接即可访问文章目录)

1、《C#串口通信从入门到精通》
2、《C#与PLC通信从入门到精通 》
3、《C# Modbus通信从入门到精通》
4、《C#Socket通信从入门到精通 》
5、《C# MES通信从入门到精通》
6、《winform控件从入门到精通》
7、《C#操作MySql数据库从入门到精通》