【问题标题】:MVVM and DataTemplatesMVVM 和数据模板
【发布时间】:2011-09-27 19:36:36
【问题描述】:

我曾问过一个关于将多个视图模型映射到单个视图的问题 (here)。我得到了一些很好的答案,但我仍然无法将在那里学到的知识应用到我的特定案例中。

简要回顾一下:我想创建一个基础 ItemViewModelBase 类,该类公开我的视图将绑定到的属性。然后我将创建两个特定的视图模型,PeopleViewModel 和 CarsViewModel。这两个都继承自 ItemViewModelBase 并实现了相应的属性。现在,我希望能够创建一个视图,该视图将根据绑定到的视图模型显示适当的信息。由于 PeopleViewModel 和 CarsViewModel 都公开了相同的属性,并且我希望这两个视图的视图看起来相同,因此我只需要一个视图。

我之前的问题中的一个答案建议使用 DataTemplate:

<DataTemplate DataType="{x:Type ItemViewModelBase}">
   //some user control
</DataTemplate>

我不熟悉将 DataTemplates 与 MVVM(以及一般的 MVVM)一起使用,所以我有几个问题:

现在 ItemViewModelBase 是一个抽象类,我定义了适当的属性(ItemName、Items 等)。我的 Items 属性是 ObservableCollection:

public virtual ObservableCollection<???> Items { get; set; }
  • 我会将什么作为集合类型?从这个基类派生的类将有不同的列表(Person、Car)。基础视图模型是放置属性的正确位置吗?我确实希望所有派生类都实现它,所以看起来如此。而且让 Person 和 Car 扩展一些基础对象是没有意义的。

  • 假设我不需要对我的视图进行任何自定义。在这种情况下,我只需要一个视图。目前尚不清楚我将如何设置它。我应该为 ItemViewModelBase 创建一个 DataTemplate 和一个视图(用户控件)来表示它吗?现在我使用 Unity 注册我的视图模型,当创建视图时,视图模型被注入到视图中。当我尝试创建视图时,如何区分不同的视图模型?

基本上,我不知道在使用 DataTemplates 时如何显示适当的视图。现在在我的应用程序中,我有一个窗口,其中包含这样定义的选项卡控件:

<Grid>
    <TabControl TabStripPlacement="Left" ItemsSource="{Binding TabItems}"/>
</Grid>

TabControl 的样式包含以下设置器:

<Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="Content" Value="{Binding Content}"/>

TabItems 的定义如下:

public ObservableCollection<ConfigTabItem> TabItems { get; set; }

TabItems.Add(new ConfigTabItem() { Header = "People", ResolveView = (Func<object>)(() => (PeopleView)Container.Resolve(typeof(PeopleView), "peopleView")) });
TabItems.Add(new ConfigTabItem() { Header = "Cars", ResolveView = (Func<object>)(() => (CarsView)ConfigurationModule.Container.Resolve(typeof(CarsView), "carsView")) });

因此,就目前而言,我有单独的视图模型和 People 和 Cars 视图,每当单击选项卡时,都会解析相应的视图。

我想更改此设置以使用上述基本视图模型类和带有 DataTemplates 的单个视图。

任何示例代码/示例将不胜感激,它显示了一个基本视图模型类,一些扩展该基本视图模型的其他视图模型类,然后能够基于视图模型显示适当的视图(其中只有一个通用视图)。

【问题讨论】:

  • 你使用的是什么 mvvm 框架?

标签: c# wpf mvvm datatemplate


【解决方案1】:

恕我直言,您在一个问题中问得太多了。尝试让您的代码在使用或不使用 DataTemplates 的情况下工作(如果需要,让它变得 hacky),然后专注于您认为需要改进的代码的一个区域,并发布有关如何解决特定问题的问题。我开始输入答案,但很快就变得过于复杂,无法表达出总体建议。

我不确定您在关于 DataTemplates 的其他问题中是否有好的建议。我也非常关心你是如何设置 ConfigTabItem 的——它似乎是一个父视图模型,它使用容器(直接,这不是一个好习惯)来解析一个视图,它可能也有自己的视图模型。这似乎是不必要的复杂。

无论如何,再次尝试将其提炼为几个重点问题。如果其中任何一个有帮助,我最初的答案开始如下(未经编辑):


首先,我不确定我是否理解您在上一个关于 DataTemplates 的问题中给出的答案。如果您将始终绑定到 ItemViewModelBase,我不清楚您为什么需要指定 DataType(甚至是 DataTemplate)。这并不是说使用 DataTemplate 是一个坏主意,但我不确定在这种情况下我是否看到了它的必要性。

我还要说我也不确定我是否看到了继承的必要性。数据绑定在运行时工作,并且在基于 VM 类型切换 DataTemplate 之外(正如我所说,我认为你不需要),视图并不关心它绑定到什么,只要它是属性在运行时找到。

因此,一般而言,我将从您的视图模型的一个具体实现开始。让它正确绑定,然后确定您可以将它的哪些部分抽象为一个基类或接口if,这是您想要采用的方法。这不是必需的,但可能有助于使绑定要求更容易“强制执行”——例如,使用基类或接口将限制您(或其他人)更改绑定所需的属性名称。

我会把什么作为收藏 类型?派生自的类 这个基类会有不同的 列表(人,车)。是基础视图 模型放置的正确位置 财产?我确实想要所有派生的 类来实现它,所以看起来 所以。而且没有意义 人和汽车扩展了一些基础 对象。

如果您要为您的 VM 使用基类或接口,并且希望集合成为其中的一部分,则它可以简单地为 ObservableCollection&lt;object&gt; 类型。添加到其中的项目都需要具有与您在 XAML 中引用的内容相匹配的属性名称。因此,如果您只想要一个视图,则不能拥有“PersonName”和“CarName”属性;您将需要使用更通用的东西,例如“ItemName”(除非您将 DataTemplates 与 DataTypes 一起使用——这实际上是 有用的地方)。同样,您需要每个集合项都从基类型继承或实现公共接口,除非(再次)您希望在编译时强制执行。

【讨论】:

  • 谢谢菲尔。我将致力于提交更有针对性的问题。顺便说一句,如果我想要一个选项卡控件,其中每个选项卡的内容是不同的视图(及其关联的视图模型),你建议如何去做(而不是我对 ConfigTabItem 所做的)?
  • 从您发布的代码看来,这些选项卡似乎必须事先知道。如果这是真的,您可以在 XAML 中以声明方式创建选项卡项,而不是以编程方式。
【解决方案2】:

查看 Microsoft App Studio 的通用应用架构。根据 Microsoft 的 App Studio,DataTemplates 应该位于 Views Directory 下的 DataTemplates 子目录中。通用应用程序对于 Windows UI 和 Windows Phone UI 都有这个目录,因此它不在共享项目中,因为它们不相同。不要使用 Converge PRISM 架构。它的设计完全错误!这并不是在考虑 Windows 和 Windows Phone 架构的情况下编写的,但就像他们称之为 Converged 一样。它应该像在 Microsoft 的 App Studio 中一样完全重新设计。不要寻找它不在其中且不需要的依赖注入。大多数将依赖注入用于存根或假接口。设计数据的 DataContext 现在与 json 数据配合得非常好,以至于依赖注入组件将是多余的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-31
    • 2016-11-22
    • 1970-01-01
    相关资源
    最近更新 更多