在 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 Children
var 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);
// DataTemplate
var dataTemplate = new DataTemplate
{
VisualTree = stackPanelFactory
};
// DataGridTemplateColumn
var templateColumn = new DataGridTemplateColumn
{
CellTemplate = dataTemplate
};
_dataGrid.Columns.Add(templateColumn);
// DataGrid
_dataGrid.Name = "MyDataGrid";
_dataGrid.AutoGenerateColumns = false;
// Add the DataGrid into RootGrid
RootGrid.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);