【问题标题】:Path for separating out the view layer from an existing winforms app?从现有的winforms应用程序中分离视图层的路径?
【发布时间】:2013-05-11 22:21:18
【问题描述】:

给定:

  1. 我们的组织有一个标准的窗体应用程序
  2. 表单和业务逻辑交织在一起——即Autonomous View。我们知道自治视图模式使编写单元测试变得困难。目标是采用单一表单并将表示逻辑与表单本身分离,以便我们拥有一个独立的域实体/对象,可以更轻松地针对它编写单元测试。
  3. 我们没有进行完全重写。我正在研究一种渐进的方法,允许单独处理一个屏幕。
  4. 经过一些研究,我认为Presentation Model 模式或MVVM 模式最适合这个组织的工作方式。
  5. 该组织通常更喜欢较少的间接层,因此更简单(即使不太健壮)更好。
  6. 从过去到现在的过渡应该是公式化的(易于教授任何已经熟悉内部概念的开发人员)。这就是为什么他们希望坚持使用 Windows 窗体而不是 WPF 等其他新技术。
  7. 域模型对视图(表单)一无所知。该表单将完全了解域模型的更改。这使得 2 层间接。再多 1 个就可以了(这就是我允许 MVVM 的原因)。

我发现的大多数 MVVM 示例都说明了它如何与 WPF 配合使用,而不是与普通的旧 Windows 窗体配合使用。

两个问题:

考虑到这一切,我所说的有没有让你认为我没有走上正确的道路或者我走错了路?我希望向管理层提出一些建议。

最后,你知道一个很好的在线代码示例可以帮助我充实原型吗?

【问题讨论】:

  • winforms 不支持 MVVM。 MVVM 实际上是专门为 WPF 创建的,主要基于 Martin Fowler 的 Presentation Model
  • 如果您希望 winforms 支持 MVVM,您将需要一个基于 winforms 的框架,支持诸如 (Real) DataBinding、DataTemplates、DataTriggers 等。没有这些概念,MVVM 就无法存在。没有这样的框架,所以你必须自己创建它。这是一项巨大的努力,无论如何都没有任何意义。这就像为 QBasic 创建一个 Windows UI 框架。
  • 感谢 HighCore。我敢肯定,那里有一种混合(或替代方法)可以做我所要求的事情(即使 WPF 是 MVVM 的自然伴侣)。我很想知道任何想跨过这座桥的人的见解。
  • MVP 模式将更适合您的要求,并且可以逐步实施。

标签: .net winforms design-patterns mvvm separation-of-concerns


【解决方案1】:

在 WPF 中,我们可以在视图中的对象和 ViewModel 中的内容之间进行数据绑定,因为 MVVM 是 WPF 的完美模式。

我从这个例子中学习了 MVVM:http://www.scottlogic.co.uk/blog/colin/2011/05/a-simple-windows-phone-7-mvvm-tombstoning-example/

这是一个 Windows Phone 教程,但如果您了解它的工作原理,您可以轻松地将它与任何 WPF 应用程序一起使用。

【讨论】:

    【解决方案2】:

    也许您能做的最好的事情就是着眼于single responsibility principle 来查看您的代码库。自治视图(以及支持它的 winforms)如此难以测试的主要原因之一是因为开发人员倾向于将所有内容集中在一个事件处理程序中。

    在 SO - https://stackoverflow.com/questions/16599778/asp-net-mvc3-linq-make-multiple-related-rows-fields-in-a-1-to-many-relationshi 上提出这个问题,它是关于 MVC3,但它完全是一团糟 - 一种负责配置 gridview、配置响应和检索数据以填充 gridview 的方法。甚至很难知道从哪里开始回答问题,更不用说编写任何合理的(阅读:简洁和快速执行)测试以确保解决方案有效。

    如果您可以仔细检查您的代码,并仔细地将所有业务逻辑和/或集成点封装到服务/组件/接口(和实现)中,最好在外部单独的程序集中。

    一旦您将所有逻辑分解为单独的组件,每个组件都专注于它自己的concern,您就可以为 then 编写测试以确保它们执行预期的任务,而无需测试应用程序的任何其他部分,这些将是您的服务。您希望将每种服务类型拍摄为由实现支持的接口。

    在编写和测试完所有这些不同的项目和程序集后,您可以使用inversion of controldependency injection 的一种形式)将它们重新引入您的应用程序。这进一步将您的 UI 与您的应用程序要执行的各种业务逻辑分离。这里的梦想是,您将到达一个地方,当您准备好重写 UI 时,您可以重用已经编写和测试的业务逻辑组件。

    我认为 winform 类将有一个接受许多参数的构造函数(上面讨论的各种服务的混合)。 DI 框架将负责为 winform 类提供服务。之后,理想情况下,您的 winforms 事件处理程序将相对较小,只需使用从各种表单字段收集的参数值调用服务方法。

    这是一篇关于在 winforms 中使用 Castle Windsor(依赖注入框架)的帖子:Using Castle.Windsor with Windows Forms Applications。有许多不同的 DI 框架,我使用 Castle Windsor 是因为它是我第一次学习的,它们本质上都做同样的事情,所以,你需要做的就是找到一个你觉得舒服的。

    这是一个基于 Web 应用程序的separation of concerns tutorial,但对于如何从现有的“厨房水槽”应用程序中识别和重构服务应该具有指导意义。

    这个答案正在变成一本书,而且非常抽象。主要的是你需要将应用程序视为一组乐高积木,你可以将它们组合起来产生功能(每个积木都是一个问题),而 UI 只是将积木粘合在一起的粘合剂(这个类比并不完美) .

    真的,它更像是艺术而不是科学,但是你可以训练你的思维以这种方式看待问题,一旦你这样做了,编程通常会变得容易得多。曲线有点陡,但是,坚持下去,你会到达那里。

    【讨论】:

    • 感谢您抽出宝贵时间提供您的见解。我确信我们这里的团队(包括我自己)可以制定一种将业务逻辑提取到自己的层中的方法。我要问的主要问题是避免重新发明是否有一些已经尝试和完善的方法有合理的原则。无论如何,你的观点都很好。谢谢。
    【解决方案3】:

    我认为您最好的选择是将ElementHosts 放入您现有的 winforms 应用程序中,并将 WPF 内容放入其中。然后您可以使用 WPF 和 MVVM 并逐步将您的 winforms 应用升级到 WPF。

    即使您在 winforms 中使用某种辅助框架,您也总是会遇到一些限制,这些限制会导致肮脏、骇人的解决方案污染您想要达到的清洁度。

    例如,winforms 中没有任何东西可以提供与 WPF ItemsControlDataTemplates 相同的功能。在 WPF 中查看ListBoxthis example 和一些DataTemplates。无论您合并了多少第三方框架,您都无法在带有ListBox 的winforms 中实现类似的功能。

    底线:把ElementHosts和WPF内容放在每个Form里面,你就可以逐渐把所有winforms的乱七八糟的东西清理成一个干净的、MVVM、可测试的、独立于分辨率的、简单漂亮的WPF UI。我坚持(而且还没有人能够证明我错了)这是从 winforms 中获得任何体面的唯一方法。

    【讨论】:

    • 感谢您的周到反馈,但这家商店不想迁移到 WPF。这家商店有几个企业级应用程序都建立在相同的内部框架之上。许多开发人员都希望转向更新的技术,但这不是我们的决定。
    【解决方案4】:

    我不想成为回答自己问题的人,但额外的研究和实验已经说明了一些问题。

    理想的解决方案是领域对象的提取本身在本质上与组织中使用的设计实践非常相似。从本质上讲,它会将所有 UI 荣耀中的视觉形式提取为更抽象的形式(“VM”或视图模型),体现形式(组合、按钮等)上使用的概念,而无需使用实际的用户控件。然后,VM 将绑定到实际找到控件的视图。

    不幸的是,这是一项艰巨的工作,其中抽象必须足够健壮,才能以与它们映射到的控件类似的方式运行。由于我们的组织有几十个自定义控件,这可不是一个简单的订单。

    以一个简单的内部组合框为例。组合表示具有一组受限选择选项的输入。我们的数据模型是一个内存数据集。该组合绑定到一个特定的表格,并且当用户填写表格并因此提供标准时,他允许的选择被进一步过滤。该组合向用户显示一个值 (DisplayMember) 并将另一个值持久保存到数据库 (ValueMember)。可能不止于此。但是,组合的“字段”抽象必须考虑其中一些概念,以便最终可以正确映射到视图。此外,我们的表单订阅了大量源自其控件的事件。这些必须以某种方式映射。所以在我看来,大量的表单(视图)功能必须在 VM 中有对应的功能。因此,VM 在某种程度上成为它所代表的物理形式的影子。

    我最初认为可以提取表单及其组成控件的非常一般的抽象,然后将该抽象(与原始表单非常相似)映射到视图。虽然有可能,但我现在认为这是不切实际的,而且它本身可能会带来很多新问题。

    因此,虽然我想避免针对实际表单实例运行测试,但我认为这可能比尝试添加抽象层更好。构建这种抽象类似于使用另一种范式重写我们的屏幕,从而不保留屏幕的原始形状。也就是说,即使我们可能一次重写一种形式从而允许逐渐过渡,最终版本也不会像希望的那样重用原始结构。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-10
      • 1970-01-01
      • 2017-03-29
      相关资源
      最近更新 更多