【问题标题】:MVVM view model designMVVM 视图模型设计
【发布时间】:2013-09-01 14:25:08
【问题描述】:

我目前正在尝试围绕MVVM-Pattern 前进。此外,我使用PRISM 来支持 IoC 等。但有一点(除其他外)特别是,我对自己的做法感到不舒服,因为这对我来说似乎有点奇怪,所以可能我没听懂。

假设我想创建一个 ListView 来显示数据库架构的一部分。因此,在“顶级”上,每个数据库都有一个元素。在这些元素中,我想显示该数据库中的表以及该表的列名。

我现在这样做的方式是创建 3 个视图模型(+1 Base-ViewModel 用于托管 ListView 的视图)。 ListView 的每个“层”一个。所以我会有 f.e.一个DatabaseViewViewModel、一个DatabaseTableViewViewModel和一个DatabaseTableColumnViewViewModel(这里的名字不太热)。

所以 Base-ViewModel 有一个 DatabaseViewViewModels 的 ObservableCollectionDatabaseViewViewModel 有一个 DatabaseTableViewViewModels 的 ObservableCollection 等等。

显然,这些视图模型需要一些配置数据(DatabaseTableViewViewModel f.e. 需要知道它的数据库)。在我看来,一个对象应该在创建后完全初始化,所以我想在构造函数中传递该数据。当然,这使得从 IoC 容器中解析这些视图模型成为不可能。但我“必须”解决它,因为它们有一些依赖项需要解决(例如 IEventAggregator)。

据我所知,处理此问题的(或至少一种)方法是使用Factories 创建视图模型,但我对这种布局不太满意。它似乎有点“过大”。

所以我想问你,我是否可能忽略了一些事情。 我的视图模型设计是否有效?或者您将如何为这种“分层”ListView 设计您的视图模型?

编辑:澄清:我创建这 3 个不同的视图模型的原因是,我认为它有点混乱(事实上,我很难想出一个想法当您尝试在层次结构中进一步暴露对象的属性(例如列名)以进行数据绑定时,我完全不知道如何实现这一点。

当然,我可以在我的模型类中使用依赖属性或实现INotifyPropertyChanged——这实际上可能是一个新项目的好方法——但假设你有一个模型,那是不可能的很容易修改。

Edit2:关于 Sheridan 对怪异视图模型类的评论,这是因为在我正在开发的应用程序中,数据库架构是我的数据。我没有处理数据库中的实际数据。 (我正在为 Microsoft 的 Forefront Identy Manager 开发一个 MySQL 管理代理。该管理代理需要知道当前从 XML 文件中读取的数据库模式(关系等)。所以我正在构建一个 UI 来轻松创建所述 XML 文件。如果我使用数据库中的实际数据,视图模型肯定看起来完全不同。

【问题讨论】:

  • 请原谅我的吹毛求疵,但我无法抗拒命名约定中有很多冗余的想法。 ViewModel 是视图的模型。那么ViewViewModel 是什么?视图的视图模型?这里太多了。 :) 也许这就是让你头脑混乱并阻碍对 MVVM 理解的原因?
  • :) 是的,我同意,这有点愚蠢。这个想法是,假设我有一个DatabaseView 和一个相应的视图模型。所以我称之为DatabaseView(_)ViewModel
  • 我明白了,但我认为你会同意拥有:Database(模型)、Database(_)ViewDatabase(_)ViewModel,因为它至少反映了对象的角色。
  • 绝对!事实上,当我想到它时,称它为...ViewViewModel 可能意味着视图和视图模型之间的耦合,避免这种耦合是 mvvm 的重点...... :)

标签: c# wpf mvvm inversion-of-control prism


【解决方案1】:

首先,我认为您不需要三个视图模型。这些应该是“模型”。 DataBaseModel 将是包含 TableModel 列表的父模型,而 TableModel 又包含 ColumnModel 列表。

然后您只需要一个 ViewModel 将具有 DataBaseModel 列表,并且此 viewmodel 将用作您的视图的 Datacontext。视图模型将具有默认构造函数,因此可以解析。为了初始化 DatabaseModel,使用配置提供连接字符串来初始化它。

对于层次结构,使用带有 HierarchicalDataTemplates 的 TreeView 来显示层次结构。

【讨论】:

  • 只有一个视图模型的问题是,当您想要公开 TableModel 或 ColumnModel 的属性以进行数据绑定时,它会变得有点混乱。这就是我使用提到的 3 个模型的原因。有什么想法吗?
  • 您可以直接绑定到模型属性。使您的模型 INotifyPropertyChanged 并且其中的任何更改都将通知给视图。
【解决方案2】:

根据经验,对于那些在编译时已知的依赖项,我使用 IoC 容器来配置它们并将它们注入到相关的类中。对于那些需要运行时信息的依赖项(例如数据库的选择),我注入了一个静态配置的工厂,使我能够在运行时创建这些对象。

为此,我不认为工厂的使用“过大”。

重要的是以正确的方式为您的视图模型建模,您似乎正在这样做。数据库包含表 - 因此您的视图模型应该(并且确实)反映了这一点。我认为你走在正确的道路上!

【讨论】:

    【解决方案3】:

    我认为您可能在这里稍微走错路了...在我看来,直接在数据对象中实现INotifyPropertyChanged 接口要容易得多,而不是使用他们每个人都有单独的视图模型。您的 .NET 类不一定与您的数据库架构匹配……想想面向对象的编程:

    您的数据库可能有CompanyPersonAddress 表,但在.NET 中,您的Company 类可能包含Person 类型的集合属性,并且每个Person 类都可以有一个属性Address 类型的...所以现在我们正在构建分层数据类...非常适合在 UI 的分层控件中显示。

    现在将这个示例继续到视图模型级别,您只需要提供Company 数据类型的集合以绑定到ItemsSource 控件属性,并且可能需要提供单个Company 属性以绑定到@ 987654332@控件属性。

    在阅读您的问题时给我敲响了警钟的一件事是关于您的DatabaseViewModel...基本上不,不,不。我们应该永远看到具有此名称的视图模型(至少在大型应用程序中)。数据来自模型,而不是视图模型......我们不将我们的视图模型与我们的数据库表匹配......只使用基本的数据类型类。

    这样想……我的数据类型类为我的每个数据库表列保存所有属性,但以更 3D 或分层的方式连接。我通常为每个表设置一个 .NET 类,但弱实体或连接表通常在 .NET 中实现为一个类具有其中另一个类的类型的属性。

    模型(数据库访问)类从对数据库的调用中填充这些数据类型类,并将它们传递给视图模型类。我的视图模型类只是每个特定视图中所需的所有属性的集合,其中大多数都将数据类型类作为它们的类型。我的视图模型也有提供视图功能的方法。

    我个人觉得使用 MVVM 与 WPF 齐头并进,没有它就无法使用 WPF(最小的应用程序除外)。我觉得您可能从更多有关 MVVM 的阅读中受益,尽管您在这里收到的答案可能就足够了。

    【讨论】:

    • 感谢您的详细回答。当您可以访问模型代码时,在模型上实现 INotifyPropertyChanged 将是一种方法。但如果你不这样做呢?至于那种奇怪的视图模型类,那是因为在我正在开发的应用程序中,数据库模式是我的数据。我没有处理数据库中的实际数据。
    • 我认为拥有所有这些数据库概念的意义可能表明它是一个数据库管理类型的应用程序,而不是它直接与数据库一起工作 - 至少我希望是这样 :) 无论如何,您说 .Net 类与数据库不匹配,但虚拟机与模型不匹配的情况也是如此。在这些情况下,您所做的是为每个模型制作 ViewModel,并使用任何策略(如果有帮助,Automapper 或类似的)映射它们。关于初始化...发挥创意。使用事件聚合器。无论什么工作:P
    • 忘了补充:在视图模型中包装模型还有很多其他原因;曾经我需要在树中显示模型对象并最终包装模型,因为我需要在视图模型上展开/选择相关属性,并且还需要延迟加载子对象。
    • @AlexPaven,我完全接受一些开发人员更喜欢这样工作......我只是选择不这样做。
    • @Sheridan 我完全理解并同意,但您还能如何解决像我的第二条评论这样的问题? :) 如果你想学究气,将模型直接绑定到视图并不是真正首选的 MVVM 方式;在单独的视图模型中处理任何 UI 问题会更加灵活,如果您包装模型,您可以更轻松地做到这一点;它使架构更加解耦。当然,我总是试图逃避而不做,而且 WPF 的许多功能有助于将 UI 问题仅保留在视图中。但有时你必须这样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 2010-12-07
    • 2012-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多