首页 文章

WPF中的DataTemplates

提问于
浏览
6

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

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

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

谢谢

2 回答

  • 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}">
    

    Edit:

    是的,这绝对应该有效 . 这是一个更完整的例子:

    Main View Model

    public class MainWindowViewModel : ViewModelBase
    {
        public ObservableCollection<QuestionViewModel> QuestionViewModels { get; set; }
    
        public MainWindowViewModel()
        {
            QuestionViewModels = new ObservableCollection<QuestionViewModel>
            {
                new GenericQuestionViewModel(),
                new GeographyQuestionViewModel(),
                new BiologyQuestionViewModel()
            };
        }
    }
    

    Question View Models

    public abstract class QuestionViewModel : ViewModelBase
    {
    }
    
    public class GenericQuestionViewModel : QuestionViewModel
    {
    }
    
    public class GeographyQuestionViewModel : QuestionViewModel
    {
    }
    
    public class BiologyQuestionViewModel : QuestionViewModel
    {
    }
    

    Question User Controls

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

    Main Window

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

    Update

    Kyle Tolle指出了一个很好的简化设置 ItemsControl.ItemTemplate . 这是结果代码:

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

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

相关问题