前言
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数据库从入门到精通》