我的视图模型的属性Fields
为ObservableCollection<FieldVM>
。在使用此属性的视图中,我有一个ItemsControl
,如此:
...
<ItemsControl ItemsSource="{Binding Fields}" />
...
FieldVM
是一个抽象类,由TextFieldVM
和EnumFieldVM
等类实现。在运行时,这些FieldVM
- 实现会添加到Fields
属性中,我希望它们在我的视图中显示其相关视图。
在WPF中,这样做很简单,我一直这样做。您只需在适当的资源字典中执行此操作,一切都按预期工作:
<DataTemplate DataType="{x:Type vm:TextFieldVM}">
<v:TextFieldView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:EnumFieldVM}">
<v:EnumFieldView />
</DataTemplate>
现在,我第一次在Silverlight工作,我预计我可以做同样的事情,但DataTemplate
没有DataType
属性。我很难过。什么是Silverlight这样做的方式?
答案 0 :(得分:8)
Microsoft Prism library具有自定义DataTemplateSelector实现,请注意DataTemplate x中的类名:keys:
<ItemsControl.ItemTemplate>
<DataTemplate>
<prism:DataTemplateSelector Content="{Binding}" HorizontalContentAlignment="Stretch" IsTabStop="False">
<prism:DataTemplateSelector.Resources>
<DataTemplate x:Key="OpenQuestionViewModel">
<Views:OpenQuestionView DataContext="{Binding}"/>
</DataTemplate>
<DataTemplate x:Key="MultipleSelectionQuestionViewModel">
<Views:MultipleSelectionView DataContext="{Binding}"/>
</DataTemplate>
<DataTemplate x:Key="NumericQuestionViewModel">
<Views:NumericQuestionView DataContext="{Binding}"/>
</DataTemplate>
</prism:DataTemplateSelector.Resources>
</prism:DataTemplateSelector>
</DataTemplate>
</ItemsControl.ItemTemplate>
答案 1 :(得分:7)
使用值转换器将类型绑定到每个视图的可见性:
<DataTemplate>
<Grid>
<v:EnumFieldView
Visibilty="{Binding Converter={StaticResource ViewVisibilityConverter}, ConverterParameter=Enum}" />
<v:TextFieldView
Visibilty="{Binding Converter={StaticResource ViewVisibilityConverter}, ConverterParameter=Text}" />
</Grid
</DataTemplate>
在ViewVisibilityConverter的ConvertTo中,根据类型切换可见性。
另一种看待它的方法是使用不同类型的值转换器从Application.Resources返回不同的数据模板。
<ListBox ItemTemplate="{Binding Converter={StaticResource ItemTemplateFactory}"/>
在ItemTemplateFactory.Convert()中:
var fieldVM = value as FieldVM;
switch fieldVM.FieldType:
{
case "Text":
return Application.Current.Resources["TextTemplate"] as DataTemplate;
case "Enum":
return Application.Current.Resources["EnumTemplate"] as DataTemplate;
}
答案 2 :(得分:5)
Silverlight 5最终将包含此功能。在此之前,明确的答案是我见过的更好的方法之一。
答案 3 :(得分:4)
Michael的第二个选项的变体(因为我无法直接使用它)。
在资源中定义一个额外的datatemplate:
<DataTemplate x:Key="DynamicTemplate">
<ContentPresenter ContentTemplate="{Binding Converter={StaticResource TemplateChooser}}" Content="{Binding}"/>
</DataTemplate>
然后在列表框中使用此数据模板
<ListBox ItemTemplate="{StaticResource DynamicTemplate}">
TemplateChooser必须是IValueConvertor,其中Convert函数接受一个对象并返回应该用于该对象的DataTemplate。
答案 4 :(得分:3)
Silverlight没有DataTemplateSelector,但我使用了这段代码......
<ItemsControl.ItemTemplate>
<DataTemplate>
<client:TemplateSelector Content="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
这是模板选择器:
public class TemplateSelector : ContentControl
{
protected override void OnContentChanged(object oldContent, object newContent)
{
base.OnContentChanged(oldContent, newContent);
MyObject f = newContent as MyObject;
switch (f.MyProperty)
{
case "Bool":
case "String":
case "Array":
default:
ContentTemplate = Application.Current.Resources["MultiSelectDataTemplate"] as DataTemplate;
break;
}
}
}
答案 5 :(得分:0)
这篇博客文章:http://www.c-sharpcorner.com/Blogs/1937/展示了一个看起来像是一个很好的自己动手的数据模板选择器伪装成一个值转换器。它的优点是不需要安装Prism。
答案 6 :(得分:-4)
您是否尝试忽略DataType属性? 并写下这样的东西:
<DataTemplate>
<v:TextFieldView />
</DataTemplate>
为我工作