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.