У меня есть модель представления со свойством 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
не имеет a DataType
свойство. Я озадачен. Каков путь Silverlight сделать это?
Используйте конвертер значений для привязки типа к видимости каждого вида:
<DataTemplate>
<Grid>
<v:EnumFieldView
Visibilty="{Binding Converter={StaticResource ViewVisibilityConverter}, ConverterParameter=Enum}" />
<v:TextFieldView
Visibilty="{Binding Converter={StaticResource ViewVisibilityConverter}, ConverterParameter=Text}" />
</Grid
</DataTemplate>
А в ConvertTo конвертера ViewVisibilityConverter переключите видимость на основе типа.
Другой способ посмотреть на это - использовать другой тип конвертера значений, чтобы вернуть другой шаблон данных из Application.Resources.
<ListBox ItemTemplate="{Binding Converter={StaticResource ItemTemplateFactory}"/>
in 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;
}
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;
}
}
}
Вариант второго варианта от Михаила (поскольку у меня не получилось заставить его работать напрямую).
В ресурсах определите дополнительный шаблон данных:
<DataTemplate x:Key="DynamicTemplate">
<ContentPresenter ContentTemplate="{Binding Converter={StaticResource TemplateChooser}}" Content="{Binding}"/>
</DataTemplate>
А затем используйте этот шаблон данных в списке
<ListBox ItemTemplate="{StaticResource DynamicTemplate}">
TemplateChooser должен быть IValueConvertor, где функция Convert принимает объект и возвращает DataTemplate, который должен использоваться для этого объекта.