WPF中的DataTemplates

时间:2012-02-03 18:11:04

标签: c# wpf mvvm datatemplate

我对WPF中的数据模板有一般性问题。假设我有一个名为“问题”的抽象类,以及各种子类,如“MathQuestion”,“GeographyQuestion”等。在某些情况下,使用“问题”数据模板将问题呈现为“问题”已经足够了,但是假设我有一个不同子类的随机问题对象列表,我想反过来显示它们。我想使用他们的特定数据模板而不是他们的通用问题数据模板向用户显示它们,但由于我不知道在设计时,无论如何都要告诉WPF,“嘿,这是一个Quesitons列表,但是使用反射来确定他们的特定类型并使用那个数据模板?“

到目前为止我的想法:我认为除了我的问题集之外,我可以使用反射创建另一个特定类型的集合,并以某种方式将其绑定到“blah”,然后我得到了所需的影响,但你只能绑定到WPF中的DependencyProperties,所以我不确定我绑定到什么。我真的不喜欢这个想法,我的直觉告诉我有一个更优雅的方法来解决这个问题。

我不是在这里寻找具体的代码,只是完成我想要做的事情的一般策略。另外,如果有帮助的话,我大部分时间都在使用MVVM。

由于

2 个答案:

答案 0 :(得分:13)

我认为这样的东西应该可以直接使用:

<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>

<强>更新

Kyle Tolle指出了设置ItemsControl.ItemTemplate的一个很好的简化。以下是生成的代码:

<ItemsControl ItemsSource="{Binding QuestionViewModels}"
              ItemTemplate="{Binding}" /> 

答案 1 :(得分:4)

通常,如果您需要根据某些非静态逻辑动态更改DataTemplate,则需要使用DataTemplateSelector。另一种选择是在DataTemplate中使用DataTriggers来适当地修改外观。