WPF ContentTemplateSelector странность

Цель: я хочу иметь объект, содержащий мои данные, и привязать его к ContentPresenter, который использует пользовательский ContentTemplateSelector, чтобы выбрать подходящий шаблон данных для рендеринга в главном элементе управления.

Проблема: DataTemplate не отображается должным образом в основном элементе управления; Он не отображает указанный элемент управления View.

Код:

MainView.xaml:

<Window x:Class="WpfContentTemplateSelector.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:this="clr-namespace:WpfContentTemplateSelector"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <this:ObjectWrapper x:Key="wrapper"/>
        </Grid.Resources>

        <ContentPresenter Content="{Binding Value}" DataContext="{StaticResource ResourceKey=wrapper}">
            <ContentPresenter.ContentTemplateSelector>
                <this:TemplateSelector/>
            </ContentPresenter.ContentTemplateSelector>
        </ContentPresenter>
    </Grid>
</Window>

DataObject.cs:

class DataObject
{
    public string Title { get; set; }

    public DataObject()
    {
        Title = "Title";
    }
}

ObjectWrapper.cs:

class ObjectWrapper
{
    public DataObject Value { get; set; }

    public ObjectWrapper()
    {
        Value = new DataObject();
    }
}

TemplateSelector.cs:

class TemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        DataTemplate template = new DataTemplate(typeof(View));

        return template;
    }
}

View.xaml:

<UserControl x:Class="WpfContentTemplateSelector.View"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:this="clr-namespace:WpfContentTemplateSelector"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" Background="Navy">
    <Grid Background="Navy">
        <Button Height="30" Content="{Binding Title}"/>
    </Grid>
</UserControl>

Резюме:

  • ObjectWrapper инициализирует.
  • DataObject инициализируется.
  • При инициализации TemplateSelector создает новый шаблон данных.
  • Созданный DataTemplate использует тип View в своем конструкторе.
  • Все объекты инициализированы, текст данных основного представления установлен на DataObject, и представление все еще не отображается в главном окне.

2 ответа

Решение

Ваша проблема в том, что в вашем TemplateSelector вы определяете DataTemplate для типа View но вы не даете ему никакого содержания. Ваш код эквивалентен следующему:

<ContentPresenter Content="{Binding Value}" DataContext="{StaticResource ResourceKey=wrapper}">
    <ContentPresenter.ContentTemplate>
        <DataTemplate DataType="this:View">
        </DataTemplate>
    </ContentPresenter.ContentTemplate>
</ContentPresenter>

Здесь вы просто определяете пустой DataTemplate для типа View, когда то, что вы на самом деле хотите, это DataTemplate, содержащий View управления:

<ContentPresenter Content="{Binding Value}" DataContext="{StaticResource ResourceKey=wrapper}">
    <ContentPresenter.ContentTemplate>
        <DataTemplate>
            <this:View />
        </DataTemplate>
    </ContentPresenter.ContentTemplate>
</ContentPresenter>

Итак, что вам нужно сделать, это изменить ваш TemplateSelector вернуть правильное DataTemplate объект.

Ответ Ади Лестера показал, что дочерние узлы для объекта DataTemplate, который я создавал, не отображали представление, используемое в конструкторе.

Чтобы добавить к визуальному дереву DataTemplate в выделенном фрагменте кода, я добавил в свой объект TemplateSelector следующий код:

class TemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        View view = item as View;
        DataTemplate template = new DataTemplate(typeof(View));

        FrameworkElementFactory factory = new FrameworkElementFactory(typeof(View));
        template.VisualTree = factory;

        return template;
    }
}

Это успешно изменяет визуальное дерево и отображает представление, используя мой собственный TemplateSelector для предоставления DataTemplate.

Другие вопросы по тегам