1

我有以下设置:

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

我想要完成的是动态决定在运行时使用哪个视图,基于DataContext. ListBox简单来说,我想替换<view:ViewName>为返回正确视图的数据绑定。

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

我已经研究了解决方案,但结果是空的。

4

2 回答 2

2

由于要根据绑定值更改模板,因此可以使用 a来DataTrigger确定ContentTemplateListBoxItem

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

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

如果要根据对象类型更改模板,可以使用 Implicit DataTemplates。这些是DataTemplates定义 a DataType,但 no的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来查找其中的匹配模板Application.Resources

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

<Style TargetType="{x:Type ListBoxItem}">
    <Setter Property="ContentTemplate" 
            Value="{Binding SomeProperty, 
                Converter={StaticResource MyTemplateConverter}}"/>
</Style>
于 2013-03-26T19:10:00.703 回答
1

使用这篇文章DataTemplateManager中的您可以执行以下操作:

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

然后你会ItemTemplate从 ListBox 中删除:

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

在 ListBox ViewModel 中,您可以:

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

然后,DataTemplateWPF 会自动使用 each 来渲染每个对应的 ViewModel。

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

编辑:

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

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

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

于 2013-03-26T18:34:55.903 回答