Альтернатива 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>

работал у меня