如何使用 C# 创建 DataTemplate 并设置子控件的资源?

How to create a DataTemplate using C# and set child control's resources?

我将如何着手为代码中的特定控件创建一些资源?

此数据模板定义列表视图的列应如何显示其内容。但是,由于此视图的特殊性质,我必须在代码中创建列以正确分配所需的属性。一切正常,唯一的例外是我还没有找到在代码中将内容控件的内部数据模板分配给内容控件的资源字典的正确方法(这是必需的,因为它根据绑定的类型而变化,想象一下“...”中定义的其他模板。我唯一缺少的部分是来自 xaml.

<ContentControl.Resources> 的 "translation"
<DataTemplate>
    <ContentControl Content="{Binding}" Focusable="False">
        <ContentControl.Resources>
            <DataTemplate DataType="{x:Type data:DataItem}">
                <StackPanel Orientation="Horizontal">
                    <TextBox Text="{Binding FirstProperty}"/>
                    <Label Content=" - "/>
                    <TextBox Text="{Binding SecondProperty}"/>
                </StackPanel>
            </DataTemplate>
            ...
        </ContentControl.Resources>
    </ContentControl>
</DataTemplate>

这是我目前的 cs 代码:

private DataTemplate GenerateSomeTemplate()
{
    DataTemplate template = new DataTemplate(typeof(TextBlock));
    FrameworkElementFactory contentElement = new FrameworkElementFactory(typeof(ContentControl));
    template.VisualTree = contentElement;
    contentElement.SetBinding(ContentControl.ContentProperty, new Binding() { }); // Might be wrong
    contentElement.SetValue(ContentControl.FocusableProperty, false);

    var displayTemplate = new DataTemplate(typeof(DataItem));
    var layout = new FrameworkElementFactory(typeof(StackPanel));

    var textBoxFirst = new FrameworkElementFactory(typeof(TextBox));
    textBoxFirst.SetBinding(TextBox.TextProperty, new Binding() { Path = new PropertyPath("FirstProperty") });
    layout.AppendChild(textBoxFirst);

    var dashLabel = new FrameworkElementFactory(typeof(Label));
    dashLabel.SetValue(Label.ContentProperty, " - ");
    layout.AppendChild(dashLabel);

    var textBoxSecond = new FrameworkElementFactory(typeof(TextBox));
    textBoxFirst.SetBinding(TextBox.TextProperty, new Binding() { Path = new PropertyPath("SecondProperty") });
    layout.AppendChild(textBoxSecond);

    displayTemplate.VisualTree = layout;

    // contentElement.AddResource(displayTemplate); // I need something like this...

    return template;
}

FrameworkElementFactory:

This class is a deprecated way to programmatically create templates, which are subclasses of FrameworkTemplate such as ControlTemplate or DataTemplate; not all of the template functionality is available when you create a template using this class. The recommended way to programmatically create a template is to load XAML from a string or a memory stream using the Load method of the XamlReader class.

这意味着,您应该使用 XmlReader 从字符串中激活 DataTemplate

var dataTemplateString = 
  @"<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" 
                  xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">    
      <ContentControl Content=""{Binding}"" Focusable=""False"">
        <ContentControl.Resources>
          <DataTemplate DataType=""{x:Type data:DataItem}"">
            <StackPanel Orientation=""Horizontal"">
              <TextBox Text=""{Binding FirstProperty}""/>
              <Label Content="" - ""/>
              <TextBox Text=""{Binding SecondProperty}""/>
            </StackPanel>
          </DataTemplate>
        </ContentControl.Resources>
      </ContentControl>
    </DataTemplate>";

var stringReader = new StringReader(dataTemplateString);
XmlReader xmlReader = XmlReader.Create(stringReader);
DataTemplate dataTemplate = (DataTemplate) XamlReader.Load(xmlReader);

或者,您可以使用 XamlWriter.Save() and then actually activate it using XamlReader.Load() (Serialization Limitations of XamlWriter.Save).

序列化现有的 DataTemplate

还有一个异步实现可以在运行时加载 XAML 个对象:XamlReader.LoadAsync