Шаблоны данных в WPF - PullRequest
       10

Шаблоны данных в WPF

6 голосов
/ 03 февраля 2012

У меня общий вопрос о шаблонах данных в WPF. Допустим, у меня есть абстрактный класс с именем «Вопрос» и различные подклассы, такие как «MathQuestion», «GeographyQuestion» и т. Д. В некоторых случаях отображение вопросов в виде «Вопроса» с использованием шаблона данных «Вопрос» достаточно хорошо, но скажем, у меня есть список случайных объектов Вопроса различных подклассов, которые я хочу отображать по очереди. Я хочу показать их пользователю, используя их конкретные шаблоны данных, а не их общий шаблон данных Вопроса, но, поскольку я не знаю, что во время разработки, есть ли возможность сказать WPF: «эй, вот список Quesitons, но использовать отражение, чтобы выяснить их конкретные типы и использовать ТА шаблон данных? "

То, о чем я думал до сих пор: я думал, что в дополнение к моей коллекции вопросов, я мог бы создать другую коллекцию определенных типов, используя рефлексию, и каким-то образом связать это с «бла», тогда я получил бы желаемое влияет, но вы можете связывать только DependencyProperties в WPF, поэтому я не уверен, что я буду связывать. Мне действительно не нравится эта идея, и моя интуиция говорит мне, что есть более элегантный способ решения этой проблемы.

Я не ищу конкретный код здесь, просто общую стратегию для достижения того, что я пытаюсь сделать. Кроме того, я использую MVVM по большей части, если это помогает.

Спасибо

Ответы [ 2 ]

13 голосов
/ 03 февраля 2012

Я думаю, что-то вроде этого должно работать прямо из коробки:

<UserControl.Resources>
    <DataTemplate DataType="{x:Type vm:GenericQuestionViewModel}">
        <v:GenericQuestion/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type tvm:GeographyQuestionViewModel}">
        <tv:GeographyQuestion/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type tvm:BiologyQuestionViewModel}">
        <tv:BiologyQuestion/>
    </DataTemplate>
</UserControl.Resources>

<ContentControl Content="{Binding QuestionViewModel}">

Редактировать:

Да, это определенно должно работать,Вот более полный пример:

Модель основного вида

public class MainWindowViewModel : ViewModelBase
{
    public ObservableCollection<QuestionViewModel> QuestionViewModels { get; set; }

    public MainWindowViewModel()
    {
        QuestionViewModels = new ObservableCollection<QuestionViewModel>
        {
            new GenericQuestionViewModel(),
            new GeographyQuestionViewModel(),
            new BiologyQuestionViewModel()
        };
    }
}

Модели вида вопроса

public abstract class QuestionViewModel : ViewModelBase
{
}

public class GenericQuestionViewModel : QuestionViewModel
{
}

public class GeographyQuestionViewModel : QuestionViewModel
{
}

public class BiologyQuestionViewModel : QuestionViewModel
{
}

Вопрос контроля пользователя

<UserControl x:Class="WpfApplication1.GenericQuestion" ...>
    <Grid>
        <TextBlock Text="Generic Question" />
    </Grid>
</UserControl>

<UserControl x:Class="WpfApplication1.GeographyQuestion" ...>
    <Grid>
        <TextBlock Text="Geography Question" />
    </Grid>
</UserControl>

<UserControl x:Class="WpfApplication1.BiologyQuestion" ...>
    <Grid>
        <TextBlock Text="Biology Question" />
    </Grid>
</UserControl>

Главное окно

<Window x:Class="WpfApplication1.MainWindow" ...
        Title="MainWindow"
        Height="900"
        Width="525">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:GenericQuestionViewModel}">
            <local:GenericQuestion />
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:GeographyQuestionViewModel}">
            <local:GeographyQuestion />
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:BiologyQuestionViewModel}">
            <local:BiologyQuestion />
        </DataTemplate>
    </Window.Resources>
    <ItemsControl ItemsSource="{Binding QuestionViewModels}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <ContentControl Content="{Binding}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Window>

Обновление

Кайл Толле указалприятное упрощение для установки ItemsControl.ItemTemplate.Вот полученный код:

<ItemsControl ItemsSource="{Binding QuestionViewModels}"
              ItemTemplate="{Binding}" /> 
4 голосов
/ 03 февраля 2012

Как правило, если вам нужно динамически изменять шаблон данных на основе некоторой нестатической логики, вы должны использовать DataTemplateSelector . Другой вариант - использовать DataTriggers в вашем шаблоне данных, чтобы соответствующим образом изменить внешний вид.

...