WPF中如何使用后台代码动态创建数据模板(DataTemplate)
数据模板回顾
在WPF中数据模板可以控制数据的呈现方式。
对于一些简单的数据,例如一个string,一个int,在显示时,无须额外控制 。
但是对于复杂数据类型,就需要使用数据模板来控制数据的呈现方式。
一个简单的例子
假设 我们定义了一个学生类
1 public class Student 2 { 3 public int Id { get; set; } 4 5 public string Name { get; set; } 6 }
然后定义了一个学生列表,并绑定到ListBox
1 var list = new List<Student>(); 2 list.Add(new Student() {Id = 1,Name = "意在" }); 3 list.Add(new Student() { Id = 2, Name = "奎文" }); 4 5 this.list1.ItemsSource = list;
在未使用数据模板前,显示的效果如下:
1 <ListBox Name="list1"></ListBox>
使用了数据模板,显示效果如下:
1 <ListBox Name="list2" Grid.Row="1"> 2 <ListBox.ItemTemplate> 3 <DataTemplate> 4 <WrapPanel> 5 <Label Content="{Binding Id}" FontWeight="Bold" FontSize="20"></Label> 6 <Label Content="{Binding Name}" FontFamily="Arial"></Label> 7 </WrapPanel> 8 </DataTemplate> 9 </ListBox.ItemTemplate> 10 </ListBox>
如何动态创建数据模板
官方的建议是使用 XamlReader.Load 方法从字符串或内存流加载 XAML而不是以编程的方式实现。
这里这两种方式都介绍一下
1、使用XamlReader.Load方法
创建本地XAML文件
1 <DataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><Grid><Grid.RowDefinitions><RowDefinition /><RowDefinition Height="30" /></Grid.RowDefinitions><Image Source="{Binding ImageUrl}" Width="150" Height="150" /><Label Content="{Binding Title}" FontWeight="Bold" HorizontalAlignment="Center" Grid.Row="1" /></Grid></DataTemplate>
加载XAML文件转换为数据模板并设置到控件上
1 var templateFile = Environment.CurrentDirectory + "\\template.xaml"; 2 var xaml = System.IO.File.ReadAllText(templateFile); 3 using(StringReader sr = new StringReader(xaml)) 4 { 5 XmlReader reader = XmlReader.Create(sr); 6 var template = XamlReader.Load(reader) as DataTemplate; 7 this.listbox.ItemTemplate = template; 8 }
2、使用代码创建数据模板
DataTamplate类可以被实例化,在创建一个DataTamplate对象后,我们需要设置它的VisualTree字段值
VisualTree字段需要的是一个FrameworkElementFactory类型,它可以支持模板创建。
可以看到这个类型的后缀是Factory,所以这里采用了工厂模式,工厂模式是一种常见的设计模式 ,它指的是根据给定的参数动态创建类型,以达到解耦的目的。
还是以上面同样的数据模板进行演示
首先我们创建一个DataTemplate对象
1 DataTemplate template = new DataTemplate();
创建一个Grid
1 FrameworkElementFactory gridFactory = new FrameworkElementFactory(typeof(Grid));
为Grid添加行定义
1 //创建行 2 FrameworkElementFactory row1 = new FrameworkElementFactory(typeof(RowDefinition)); 3 FrameworkElementFactory row2 = new FrameworkElementFactory(typeof(RowDefinition)); 4 row2.SetValue(RowDefinition.HeightProperty, new GridLength(30)); 5 6 //添加行 7 gridFactory.AppendChild(row1); 8 gridFactory.AppendChild(row2);
添加Image控件
1 //添加图像 2 FrameworkElementFactory imageFactory = new FrameworkElementFactory(typeof(Image)); 3 imageFactory.SetValue(Image.SourceProperty, new Binding("ImageUrl")); //Source 4 imageFactory.SetValue(Image.WidthProperty, 150d); //Width 5 imageFactory.SetValue(Image.HeightProperty, 150d); //Height 6 gridFactory.AppendChild(imageFactory);
添加Label控件
1 //添加标题 2 FrameworkElementFactory labelFactory = new FrameworkElementFactory(typeof(Label)); 3 labelFactory.SetValue(Label.ContentProperty, new Binding("Title")); //内容 4 labelFactory.SetValue(Label.FontWeightProperty, FontWeights.Bold); //加粗 5 labelFactory.SetValue(Grid.RowProperty, 1); //Grid.Row = 1 6 labelFactory.SetValue(Label.HorizontalAlignmentProperty, HorizontalAlignment.Center);//HorizontalAlignment 7 gridFactory.AppendChild(labelFactory);
最后将grid设置到DataTemplate的VisualTree上,我们就得到一个动态的数据模板(DataTemplate)对象
1 template.VisualTree = gridFactory;
运行效果
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
2021-08-22 如何知道安装程序在进行安装时对你的电脑到底做了什么?
2021-08-22 架构师笔记:康威定律