2013-03-26 86 views
1

我有以下设置:动态设置用户控件作为列表框的DataTemplate体

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

我试图做到的是动态地决定哪些查看在运行时使用的基础上,ListBoxDataContext中的属性。简单地说,我想用一个返回正确视图的数据绑定来代替<view:ViewName>

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

我已经研究了解决方案,但已经空了。

+0

你还好吗使用一些其他辅助类或类似的 - 只要你查看视图模型只是一个 - 和单一属性 - 或多个属性在您的虚拟机中。有很多解决方案,稍后我会尝试写点东西 - 我只需要知道目标是什么。例如。看到这个'flags'解决方案(解决方案2)http://stackoverflow.com/questions/15550344/genrating-views-usercontrols-using-contentcontrol/15550477#15550477 - (你可以映射这不仅仅是两个'选择等) - 但是我经常使用更好的方法。 – NSGaga 2013-03-26 18:59:21

+0

我没有使用助手/转换器/等问题。我可以使用一个解决方案,它要求我在设计时在xaml中列出所有可能的选择,因为那时我不会知道它们。我想最简单的方法来演示我需要的是为DataTemplate添加一个假设属性,如下所示:''其中View是ListBox的DataTemplate中的一个属性。 – 2013-03-26 19:05:59

+0

可能是一个包含视图名称的字符串。我认为,我可以安排所有的观点都在同一个命名空间,即使是动态的。而上面我的意思是“ListBox的DataContext”,但我刚用完编辑时间 – 2013-03-26 19:10:34

回答

1

使用DataTemplateManagerthis post你可以这样做:

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

那么你会删除ListBox中ItemTemplate

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

和ListBox中的视图模型,你可以:

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

然后,每个WPF会自动使用来呈现每个对应的ViewModel。

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

编辑:

基于您的评论,你可以创建一个单一的DataTemplate与ContentPresenter根据视图模型属性显示所选查看:

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

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

+0

这真棒,如此接近我真正想做的事情。如果必须的话,我可以使用它。但我真正想要的是基于单个视图模型中的属性选择我的视图,而不是为每个视图分别创建视图模型。我有一个类型为IAction的Action属性的TargetViewModel。实现IAction的各个具体类可以提供要显示的视图的名称。因此,在理想的世界中,ListBox将使用TargetViewModel.Action.View来确定要显示的视图。 – 2013-03-26 18:54:36

+0

这很好。我只需要意识到我需要为每个Action分别创建视图模型。无论如何,我正在试图通过IAction参考尝试与特定的Action类一起工作。通过这种方式,我有一个具有正确类型的具体操作成员的视图模型,以便我的视图可以获取所需的信息。 Action的提供者现在需要证明一个视图模型,但我将大部分工作抽象为一个基类。它效果很好,比我最初寻找的解决方案更好。谢谢! – 2013-03-27 13:59:51

2

既然你要根据绑定的值更改模板,你可以使用一个DataTrigger确定的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> 

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

如果要根据对象类型更改模板,可以使用隐式DataTemplates。这些是DataTemplates,它们定义了DataType,但没有x:Key,它们将在WPF尝试绘制指定类型的对象时随时使用。

例如,如果您曾在定义这个模板您<X.Resources>地方

<DataTemplate DataType="{x:Type models:ActionA}"> 
    <views:ActionAView /> 
</DataTemplate> 

,那么你可以直接插入你的模型对象到用户界面和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> 
+0

这实际上工作得很好,除了我在设计时不知道可能的值集合来创建静态资源。 – 2013-03-26 19:17:36

+0

@ user1394408那么你必须事先创建你的'Templates'吗?你不能只写“如果Property = Z然后使用TemplateZ”,并没有TemplateZ定义的地方。我想你可以使用'Converter'来代替DataTrigger,它会查看绑定的属性,然后在Application.Resources中搜索匹配该属性的模板并返回它。 – Rachel 2013-03-26 19:19:50

+0

@Rachel在说些什么很有意义 - 你需要在某个时候修正某些问题 - 或者你打算怎么做 – NSGaga 2013-03-26 19:23:50

相关问题