动态设置UserControl为Listbox DataTemplate正文

时间:2013-03-26 18:25:04

标签: c# wpf xaml listbox datatemplate

我有以下设置:

<ListBox ItemSource="{Binding Targets}">
    <ListBox.ItemTemplate>
        <DataTemplate>
          <view:ViewName />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

我想要实现的是根据DataContext的{​​{1}}内的属性动态决定在运行时使用哪个视图。简单来说,我想用一个返回正确视图的数据绑定替换ListBox

我使用MEF为我的应用提供插件,可能需要提供自定义视图以在适当时显示项目。在设计时我不会知道所有可能的视图类型(它们可能是从DLL动态加载的),因此简单的<view:ViewName>不会这样做。

我已经研究过解决方案但是空洞了。

2 个答案:

答案 0 :(得分:2)

由于您希望根据绑定值更改模板,因此您可以使用DataTrigger来确定ContentTemplate

ListBoxItem
<Style TargetType="{x:Type ListBoxItem}">
    <Setter Property="ContentTemplate" Value="{StaticResource DefaultTemplate}"/>
    <Style.Triggers>
        <DataTrigger Property="{Binding SomeProperty}" Value="A">
            <Setter Property="ContentTemplate" Value="{StaticResource TemplateA}"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

我发现这比使用DataTemplateSelector更好,因为如果绑定属性发生更改则会重新评估,而DataTemplateSelector则不会。

如果要根据对象类型更改模板,可以使用隐式DataTemplates。这些DataTemplates定义了DataType,但没有x:Key,并且只要WPF尝试绘制指定类型的对象,它们就会被使用。

例如,如果您在<X.Resources>某处

中定义了此模板
<DataTemplate DataType="{x:Type models:ActionA}">
    <views:ActionAView />
</DataTemplate>

然后您可以将Model对象直接插入UI,WPF将使用您指定的模板绘制它

<ContentControl Content="{Binding SomeIActionObject}" />

<ItemsControl ItemsSource="{Binding CollectionOfIActionObjects}" />

<强>更新

您提到您将允许用户创建包含使用MEF导入的其他模板的模块,因此在这种情况下,最好使用IValueConverter查找{{1}内的匹配模板}}

例如,如果绑定值等于Application.Resources,则转换器可能会在"A"中搜索名为Application.Resources的模板并将其返回到绑定

"TemplateA"

答案 1 :(得分:1)

使用this post中的DataTemplateManager您可以执行以下操作:

DataTemplateManager.RegisterDataTemplate<ViewModelType1, ViewType1>();
DataTemplateManager.RegisterDataTemplate<ViewModelType2, ViewType2>();
DataTemplateManager.RegisterDataTemplate<ViewModelType3, ViewType3>();

然后你将从ListBox中删除ItemTemplate

<ListBox ItemSource="{Binding Targets}"/>

在ListBox ViewModel中你可以:

public void AddTargets()
{
    Targets.Add(new ViewModelType1());
    Targets.Add(new ViewModelType2());
    Targets.Add(new ViewModelType3());
}

然后,WPF将自动使用每个DataTemplate来呈现每个相应的ViewModel。

另请注意,您可以在显示ListBox之前随时调用DataTemplateManager.RegisterDataTemplate(),因此理论上您可以在加载MEF部件时执行此操作。

编辑:

根据您的评论,您可以使用ContentPresenter创建单个DataTemplate,以根据ViewModel中的属性显示所选的视图:

<DataTemplate DataType="{x:Type local:TargetViewModel}">
    <ContentPresenter x:Name="MainContentPresenter" Content="{Binding}" ContentTemplate="{Binding YourProperty, Converter=SomeConverter}"/>

并且在SomeConverter中你应该使用与帖子中演示的相同的技术来动态生成DataTemplate。