在 WPF 编程中,我们通常都是在前台 XAML 中通过标记语言来编写 DataTemplate 的。曾今有小伙伴在 Stack Overflow 上提问,如何在后台通过 C# 代码来创建 DataTemplate ?我搜索了一番,找到了 FrameworkElementFactory 类,它便是生成 DataTemplate 的核心功臣。
先看一下 XAML 中实现的效果
<Grid x:Name="RootGrid"><DataGrid x:Name="MyDataGrid" AutoGenerateColumns="False"><DataGrid.Columns><DataGridTemplateColumn><DataGridTemplateColumn.CellTemplate><DataTemplate><StackPanel Orientation="Horizontal"><TextBlock Foreground="Red" Text="{Binding ValueA}"/><TextBlock Foreground="Blue" Text="{Binding ValueB}" /></StackPanel></DataTemplate></DataGridTemplateColumn.CellTemplate></DataGridTemplateColumn></DataGrid.Columns></DataGrid></Grid>
将 XAML 中的效果用 C# 来实现:
public MainWindow(){InitializeComponent();InitializeDataGrid();}private void InitializeDataGrid(){// StackPanel and Childrenvar stackPanelFactory = new FrameworkElementFactory(typeof(StackPanel));stackPanelFactory.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);var textBlockFactoryA = new FrameworkElementFactory(typeof(TextBlock));textBlockFactoryA.SetValue(TextElement.ForegroundProperty, Brushes.Red);textBlockFactoryA.SetBinding(TextBlock.TextProperty, new Binding("ValueA"));var textBlockFactoryB = new FrameworkElementFactory(typeof(TextBlock));textBlockFactoryB.SetValue(TextElement.ForegroundProperty, Brushes.Blue);textBlockFactoryB.SetBinding(TextBlock.TextProperty, new Binding("ValueB"));stackPanelFactory.AppendChild(textBlockFactoryA);stackPanelFactory.AppendChild(textBlockFactoryB);// DataTemplatevar dataTemplate = new DataTemplate{VisualTree = stackPanelFactory};// DataGridTemplateColumnvar templateColumn = new DataGridTemplateColumn{CellTemplate = dataTemplate};_dataGrid.Columns.Add(templateColumn);// DataGrid_dataGrid.Name = "MyDataGrid";_dataGrid.AutoGenerateColumns = false;// Add the DataGrid into RootGridRootGrid.Children.Add(_dataGrid);}private readonly DataGrid _dataGrid = new DataGrid();
方法1
DataTemplate template = new DataTemplate();FrameworkElementFactory factory = new FrameworkElementFactory(typeof(StackPanel));template.VisualTree = factory;FrameworkElementFactory childFactory = new FrameworkElementFactory(typeof(Image));childFactory.SetBinding(Image.SourceProperty, new Binding("Machine.Thumbnail"));childFactory.SetValue(Image.WidthProperty, 170.0 ) ;childFactory.SetValue(Image.HeightProperty, 170.0 ) ;factory.AppendChild(childFactory);childFactory = new FrameworkElementFactory(typeof(Label));childFactory.SetBinding(Label.ContentProperty, new Binding("Machine.Descriiption"));childFactory.SetValue(Label.WidthProperty, 170.0);childFactory.SetValue(Label.HorizontalAlignmentProperty, HorizontalAlignment.Center);factory.AppendChild(childFactory);
DataTemplate template = new DataTemplate();
FrameworkElementFactory factory = new FrameworkElementFactory(typeof(StackPanel));
template.VisualTree = factory;
FrameworkElementFactory childFactory = new FrameworkElementFactory(typeof(Image));
childFactory.SetBinding(Image.SourceProperty, new Binding(“Machine.Thumbnail”));
childFactory.SetValue(Image.WidthProperty, 170.0 ) ;
childFactory.SetValue(Image.HeightProperty, 170.0 ) ;
factory.AppendChild(childFactory);
childFactory = new FrameworkElementFactory(typeof(Label));
childFactory.SetBinding(Label.ContentProperty, new Binding(“Machine.Descriiption”));
childFactory.SetValue(Label.WidthProperty, 170.0);
childFactory.SetValue(Label.HorizontalAlignmentProperty, HorizontalAlignment.Center);
factory.AppendChild(childFactory);
方法二
C#
MemoryStream sr = null;
ParserContext pc = null;
string xaml = string.Empty;
xaml = “
sr = new MemoryStream(Encoding.ASCII.GetBytes(xaml));
pc = new ParserContext();
pc.XmlnsDictionary.Add(“”, “http://schemas.microsoft.com/winfx/2006/xaml/presentation“);
pc.XmlnsDictionary.Add(“x”, “http://schemas.microsoft.com/winfx/2006/xaml“);
DataTemplate datatemplate = (DataTemplate)XamlReader.Load(sr, pc);
this.Resources.Add(“dt”, datatemplate);
