在 WPF 编程中,我们通常都是在前台 XAML 中通过标记语言来编写 DataTemplate 的。曾今有小伙伴在 Stack Overflow 上提问,如何在后台通过 C# 代码来创建 DataTemplate ?我搜索了一番,找到了 FrameworkElementFactory 类,它便是生成 DataTemplate 的核心功臣。
    先看一下 XAML 中实现的效果

    1. <Grid x:Name="RootGrid">
    2. <DataGrid x:Name="MyDataGrid" AutoGenerateColumns="False">
    3. <DataGrid.Columns>
    4. <DataGridTemplateColumn>
    5. <DataGridTemplateColumn.CellTemplate>
    6. <DataTemplate>
    7. <StackPanel Orientation="Horizontal">
    8. <TextBlock Foreground="Red" Text="{Binding ValueA}"/>
    9. <TextBlock Foreground="Blue" Text="{Binding ValueB}" />
    10. </StackPanel>
    11. </DataTemplate>
    12. </DataGridTemplateColumn.CellTemplate>
    13. </DataGridTemplateColumn>
    14. </DataGrid.Columns>
    15. </DataGrid>
    16. </Grid>

    将 XAML 中的效果用 C# 来实现:

    1. public MainWindow()
    2. {
    3. InitializeComponent();
    4. InitializeDataGrid();
    5. }
    6. private void InitializeDataGrid()
    7. {
    8. // StackPanel and Children
    9. var stackPanelFactory = new FrameworkElementFactory(typeof(StackPanel));
    10. stackPanelFactory.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
    11. var textBlockFactoryA = new FrameworkElementFactory(typeof(TextBlock));
    12. textBlockFactoryA.SetValue(TextElement.ForegroundProperty, Brushes.Red);
    13. textBlockFactoryA.SetBinding(TextBlock.TextProperty, new Binding("ValueA"));
    14. var textBlockFactoryB = new FrameworkElementFactory(typeof(TextBlock));
    15. textBlockFactoryB.SetValue(TextElement.ForegroundProperty, Brushes.Blue);
    16. textBlockFactoryB.SetBinding(TextBlock.TextProperty, new Binding("ValueB"));
    17. stackPanelFactory.AppendChild(textBlockFactoryA);
    18. stackPanelFactory.AppendChild(textBlockFactoryB);
    19. // DataTemplate
    20. var dataTemplate = new DataTemplate
    21. {
    22. VisualTree = stackPanelFactory
    23. };
    24. // DataGridTemplateColumn
    25. var templateColumn = new DataGridTemplateColumn
    26. {
    27. CellTemplate = dataTemplate
    28. };
    29. _dataGrid.Columns.Add(templateColumn);
    30. // DataGrid
    31. _dataGrid.Name = "MyDataGrid";
    32. _dataGrid.AutoGenerateColumns = false;
    33. // Add the DataGrid into RootGrid
    34. RootGrid.Children.Add(_dataGrid);
    35. }
    36. private readonly DataGrid _dataGrid = new DataGrid();

    方法1

    1. DataTemplate template = new DataTemplate();
    2. FrameworkElementFactory factory = new FrameworkElementFactory(typeof(StackPanel));
    3. template.VisualTree = factory;
    4. FrameworkElementFactory childFactory = new FrameworkElementFactory(typeof(Image));
    5. childFactory.SetBinding(Image.SourceProperty, new Binding("Machine.Thumbnail"));
    6. childFactory.SetValue(Image.WidthProperty, 170.0 ) ;
    7. childFactory.SetValue(Image.HeightProperty, 170.0 ) ;
    8. factory.AppendChild(childFactory);
    9. childFactory = new FrameworkElementFactory(typeof(Label));
    10. childFactory.SetBinding(Label.ContentProperty, new Binding("Machine.Descriiption"));
    11. childFactory.SetValue(Label.WidthProperty, 170.0);
    12. childFactory.SetValue(Label.HorizontalAlignmentProperty, HorizontalAlignment.Center);
    13. 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);