如何将MVC模式应用于C#WinForms应用程序?


11

我是一名C ++开发人员,此后一直使用MVC模式来设计GUI。

最近,我想重新使用C#,并设置了Windows Forms应用程序,但现在我对如何将其推送到MVC兼容结构有些迷惑。

我当前要执行的操作是“声明”为WinForms提供的类作为视图,并在后台为Model和Controller添加类。但是,我不确定如何与事件交互,例如单击按钮。通常,我会将这些事件重定向到控制器,并在完成后对View执行操作。

但是,这对于这个星座来说是非常不满意的。例如,如果我想实现“退出”按钮,则必须将事件从View重定向到Controller,并在View中实现一个额外的公共方法,然后可以从Controller调用它,而我可以在第一个实例中简单地从View调用Close()。

您对我有什么建议吗?我对C#中的Windows窗体的理解还不够好,无法尝试MVC实现吗?我给表格课一个错误的角色吗?对于这个用例,MVC仅仅是不合适的体系结构吗?


1
OT问题。但是为什么要使用WInforms?WPF旨在替代Winforms,并支持MVC(从技术上讲是MVVM)。尽管我会说WPF的学习曲线可能很陡。(但是如果做得不好,您可以使WPF代码看起来像Winforms)
Peter M

1
@PeterM:因为即使经过10年,WPF仍然很烂,而且仍然很慢。
whatsisname

3
为了解释@whatsisname的评论,WPF面向大型应用程序。较小的应用程序可能会更好地与Winforms一起使用,因为Winforms可以说更简单。但是,如果要提出该参数,则还可以提出这样的论据,即Winforms应用程序足够小,以至于它可能根本不需要MVP。MVVM被烘焙到WPF中。WPF具有基于矢量的图形,因此它不会像Winforms一样遇到尺寸调整问题。WPF具有很强的可组合性(您可以轻松地将控件放入其他控件中),并且具有杀手级数据绑定功能。不喜欢什么
罗伯特·哈维

3
@whatsisname WPF可能很烂,但是对于玩具程序以外的东西,它的吸吮能力比Winforms少得多
Peter M

2
对于内部桌面程序,我会这样说。但是许多公司更喜欢基于浏览器的应用程序进行业务运营,这仅仅是因为不需要安装。
罗伯特·哈维

Answers:


3

碰巧的是,我正在按照MVC进行模式化的WinForms项目。我不会说这是一个完美的答案,但是我将解释我的总体设计,希望这可以帮助您提出自己的想法。

根据我在开始该项目之前所做的阅读,似乎没有实现该目标的“正确”方法。我遵循简单的OOP和MVC设计原则,其余的是我开发工作流程时的反复试验。

对于这个用例,MVC仅仅是不合适的体系结构吗?

..?您的问题中没有足够的上下文来提供直接答案。为什么首先使用MVC?您的项目的非功能性要求是什么?您的项目会占用大量UI吗?您是否更在意安全性,而不是分层架构?您的项目的主要组成部分是什么?也许每个组件都需要不同的设计模式。首先找出为什么要使用这种设计模式,然后您可能会回答自己的问题;)

我使用MVC的原因:我认为这是一个相当简单的设计模式,我的设计很大程度上依赖于用户交互。MVC允许开发人员分离关注点的方式也足以满足我的应用程序的需求。这使我的代码很多更容易维护和测试。

我还想我正在使用更多的混合设计。通常,软件工程中提出的理想概念实际上并不会在实践中发挥作用。您可以修改设计以适合您的项目需求。无需陷入对错。有一些通用的做法,但是只要您不向自己开枪,规则总是可以弯曲或折断的。

我的实现从一个高级设计开始,该设计使我对所需的组件有了一个想法。最好以这种方式开始并逐步降低体系结构。这是项目的打包图(在StarUML中创建): 在此处输入图片说明

请注意,除表示层外,每个其他层均取决于消息传递系统。这是通用的“语言”,这些层的较低层和子系统用于相互通信。就我而言,这是一个基于可以执行的操作的简单枚举。这把我带到了下一点...

将操作或命令视为实现的基础。您希望您的应用程序做什么?将其分解为最基本的操作。例如:CreateProject,WriteNotes,SaveProject,LoadProject等。GUI(或Form类)将发生一些事件(如按下按钮)。每个操作都有与之关联的控制器方法。在这种情况下,退出之类的事情太简单了。可以简单地从Form类关闭该应用程序。但是,假设我想先将一些应用程序数据保存到文件中?我将在按钮按下方法中从各个控制器类中调用“保存”方法。

从那里,控制器将从Service类调用正确的一组操作。我的应用程序中的服务类充当域层的接口。他们将验证从控制器方法调用(从而从GUI)接收的输入,并操纵数据模型。

验证和相应的对象操作完成后,服务方法将向控制器返回消息代码。例如,MessageCodes.SaveSuccess。控制器和服务类均基于域对象和/或可以分组在一起的常规操作集。

例如:(FileMenuController操作:NewProject,SaveProject,LoadProject)-> ProjectServices(CreateProject,PersistProjectToFile,LoadProjectFromFile)。Project数据模型中的域类在哪里?在我的情况下,Controller和Service类是带有静态方法的非示例类。

然后,控制器将操作识别为未成功完成。现在,控制器拥有自己的消息传递系统,可用于与表示层进行交互,因此服务层和表示层之间具有双重依赖关系。在这种情况下,控制器中总是ViewStateViewModels包中调用的类返回给GUI。此状态包含以下信息:“ 您是否试图将应用程序置于有效状态? ”,“ 关于您试图执行的操作以及为什么成功或失败的错误信息(错误消息) ”和一个ViewModel类。

ViewModel类包含从域层相关的数据,该GUI将用于更新视图。这些视图模型看起来像域类,但在我的情况下,我使用的对象非常。基本上,它们几乎没有任何行为,只是中继有关应用程序较低状态的信息。换句话说,我永远不会将我的域类放弃给表示层。这也是为什么ControllersServices包将服务层分为两部分的原因。控制器将永远不会处理域类或验证其状态。它们只是将GUI相关数据转换为服务可以使用的域相关数据的边界,反之亦然。在控制器中包含服务逻辑将导致非常 控制器,难以维护。

我希望这可以为您提供一个起点。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.