Как создать DataTemplate, используя C# и установить ресурсы дочернего элемента управления? - PullRequest
2 голосов
/ 03 марта 2020

Как бы я go о создании некоторых ресурсов для определенного элемента управления в коде?

Этот шаблон данных определяет, как столбец представления списка должен представлять свое содержимое. Однако из-за специфической природы этого представления мне необходимо создать столбцы в коде, чтобы правильно назначать требуемые свойства. Это все работает хорошо, за исключением одного случая, когда я не нашел правильного способа назначения внутреннего шаблона данных элемента управления содержимым для словаря ресурсов элемента управления содержимым в коде (это необходимо, поскольку он изменяется в соответствии с типом привязки, представьте себе, другие шаблоны, определенные в «...»). Единственная часть, которую я пропускаю - это «перевод» <ContentControl.Resources> с xaml.

<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;
}

1 Ответ

2 голосов
/ 03 марта 2020

FrameworkElementFactory :

Этот класс является устаревшим способом программного создания шаблонов, которые являются подклассами FrameworkTemplate, такими как ControlTemplate или DataTemplate; не все функциональные возможности шаблона доступны при создании шаблона с использованием этого класса. Рекомендуемый способ программного создания шаблона состоит в том, чтобы загрузить XAML из строки или потока памяти с помощью метода Load класса XamlReader.

Это означает, что вы должны использовать 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);

В качестве альтернативы вы можете сериализовать существующий DataTemplate, используя XamlWriter.Save(), а затем фактически активировать его, используя XamlReader.Load() ( Ограничения сериализации) of XamlWriter.Save ).

Также существует асинхронная реализация для загрузки объектов XAML во время выполнения: XamlReader.LoadAsync.

...