在代码后台创建数据模板

30

如何在程序中动态地向数据模板添加控件?

例如,我已经创建了一个TextBlock和DataTemplate。

TextBlock text = new TextBlock();
DataTemplate template = new DataTemplate();

现在我需要将TextBlock添加到DataTemplate中。如何实现?

我知道还有其他通过代码后台添加数据模板的方法: 1. 在XAML中创建一个数据模板,在代码后台加载它 2. 使用XamlParser创建并添加

但我需要按照我在示例中展示的方式来做。

需要一些帮助。

3个回答

43

尽管 Archedius的方法 有效,但官方已经弃用它,现在推荐以编程方式创建模板的方法是使用XamlReader类的Load方法从字符串或内存流中加载XAML,就像这样...

public DataTemplate Create(Type type)
{
    StringReader stringReader = new StringReader(
    @"<DataTemplate 
        xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""> 
            <" + type.Name + @" Text=""{Binding " + ShowColumn + @"}""/> 
        </DataTemplate>");
    XmlReader xmlReader = XmlReader.Create(stringReader);
    return XamlReader.Load(xmlReader) as DataTemplate;
}

从MSDN获悉的官方信息:http://msdn.microsoft.com/zh-cn/library/system.windows.frameworkelementfactory.aspx

Fredrik Hedblad在此帖子中提供的代码示例:Problems with XamlReader generating DataTemplate


9
请使用 System.Windows.Markup 中的 XamlReader,而不是 System.Xaml。 - Jason Rae
4
虽然另一个选项已经过时,但这种方法非常不方便,它几乎没有静态错误检查,并且产生的错误消息很晦涩(例如,在第5行第27个位置发现意外字符0x20),此外,这也意味着您无法访问项目资源。在我看来,除了最简单的模板之外,请远离这种方法。 - wondra
1
DataTemplate.VisualTree方法仍然在WPF内部用于以编程方式创建模板时,很难称替代方法为弃用方法。 - caesay

40

首先你需要声明一个 DataTemplate:

DataTemplate template = new DataTemplate { DataType = typeof(< Type of the object the template refers>) };

那么就像这样声明一个布局面板,比如StackPanel:

FrameworkElementFactory stackPanelFactory = new FrameworkElementFactory(typeof(StackPanel));
stackPanelFactory.SetValue(StackPanel.OrientationProperty, Orientation.Vertical);

最后将TextBlock部分附加到它:

FrameworkElementFactory title = new FrameworkElementFactory(typeof(TextBlock));
title.SetBinding(TextBlock.TextProperty, new Binding("< name of your binding >"));
stackPanelFactory.AppendChild(title);

为了显示以这种方式创建的StackPanel,您需要将其附加到VisualTree:

template.VisualTree = stackPanelFactory;

希望能帮到你! :)


18
我知道这是一种变通方法,但我在code project上发布了一个提示(http://www.codeproject.com/Tips/808808/Create-Data-and-Control-Templates-using-Delegates),它允许您使用委托创建数据模板。 例如:
TemplateGenerator.CreateDataTemplate(() => new TextBox());

这将足以创建一个数据模板,以创建一个新的文本框。如果你想要一个绑定,它可以像这样编写:
TemplateGenerator.CreateDataTemplate
(
  () =>
  {
    var result = new TextBox();
    result.SetBinding(TextBox.TextProperty, "PathForTheBinding");
    return result;
  }
);

模板生成器的代码如下:
/// <summary>
/// Class that helps the creation of control and data templates by using delegates.
/// </summary>
public static class TemplateGenerator
{
  private sealed class _TemplateGeneratorControl:
    ContentControl
  {
    internal static readonly DependencyProperty FactoryProperty = DependencyProperty.Register("Factory", typeof(Func<object>), typeof(_TemplateGeneratorControl), new PropertyMetadata(null, _FactoryChanged));

    private static void _FactoryChanged(DependencyObject instance, DependencyPropertyChangedEventArgs args)
    {
      var control = (_TemplateGeneratorControl)instance;
      var factory = (Func<object>)args.NewValue;
      control.Content = factory();
    }
  }

  /// <summary>
  /// Creates a data-template that uses the given delegate to create new instances.
  /// </summary>
  public static DataTemplate CreateDataTemplate(Func<object> factory)
  {
    if (factory == null)
      throw new ArgumentNullException("factory");

    var frameworkElementFactory = new FrameworkElementFactory(typeof(_TemplateGeneratorControl));
    frameworkElementFactory.SetValue(_TemplateGeneratorControl.FactoryProperty, factory);

    var dataTemplate = new DataTemplate(typeof(DependencyObject));
    dataTemplate.VisualTree = frameworkElementFactory;
    return dataTemplate;
  }

  /// <summary>
  /// Creates a control-template that uses the given delegate to create new instances.
  /// </summary>
  public static ControlTemplate CreateControlTemplate(Type controlType, Func<object> factory)
  {
    if (controlType == null)
      throw new ArgumentNullException("controlType");

    if (factory == null)
      throw new ArgumentNullException("factory");

    var frameworkElementFactory = new FrameworkElementFactory(typeof(_TemplateGeneratorControl));
    frameworkElementFactory.SetValue(_TemplateGeneratorControl.FactoryProperty, factory);

    var controlTemplate = new ControlTemplate(controlType);
    controlTemplate.VisualTree = frameworkElementFactory;
    return controlTemplate;
  }
}

它还有一个用于ControlTemplates的方法。


1
这绝对是最好的答案,也适用于复杂的DataTemplates——其他两个答案失败了。 - Coden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接