Альтернатива DataTemplate.DataType в Silverlight
У меня есть модель вида с свойством 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 сделать это?
Ответы
Ответ 1
Используйте конвертер значений, чтобы привязать тип к видимости каждого вида:
<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}"/>
в 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
Библиотека Microsoft Prism имеет пользовательскую реализацию DataTemplateSelector, обратите внимание на Classnames в 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>
Ответ 3
Silverlight 5, наконец, включит эту функциональность. До тех пор заметный ответ - один из лучших способов, которые я видел.
Ответ 4
Вариант второй опции от Майкла (так как я не мог заставить его работать напрямую).
В ресурсах укажите дополнительную таблицу данных:
<DataTemplate x:Key="DynamicTemplate">
<ContentPresenter ContentTemplate="{Binding Converter={StaticResource TemplateChooser}}" Content="{Binding}"/>
</DataTemplate>
И затем используйте этот шаблон данных в списке
<ListBox ItemTemplate="{StaticResource DynamicTemplate}">
TemplateChooser должен быть IValueConvertor, где функция Convert принимает объект и возвращает DataTemplate, который должен использоваться для этого объекта.
Ответ 5
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;
}
}
}
Ответ 6
Это сообщение в блоге: http://www.c-sharpcorner.com/Blogs/1937/ представляет, как выглядит красивый селектор шаблонов данных сам по себе, маскирующий как конвертер значений. Преимущество состоит в том, что установка Prism не требуется.
Ответ 7
Вы пытались пренебречь свойством DataType?
и просто напишите что-нибудь вроде этого:
<DataTemplate>
<v:TextFieldView />
</DataTemplate>
работал у меня