如何在Winform中正确构建项目?


26

不久前,我开始创建一个winform应用程序,当时它很小,因此我没有考虑如何构造项目。

从那时起,我根据需要添加了其他功能,并且项目文件夹越来越大,现在我认为是时候以某种方式构建项目了,但是我不确定什么是正确的方式,因此我没有什么疑问。

如何正确重组项目文件夹?

目前,我正在考虑这样的事情:

  • 创建表单文件夹
  • 创建实用程序类的文件夹
  • 为仅包含数据的类创建文件夹

添加类时的命名约定是什么?

我是否还应该重命名类,以便仅通过查看其名称即可识别其功能?例如,重命名所有表单类,以便其名称以Form结尾。还是如果为它们创建了特殊文件夹,这是否没有必要?

怎么办,以便不是主窗体的所有代码都以Form1.cs结尾

我遇到的另一个问题是,随着我添加的每个功能的主要形式越来越庞大,代码文件(Form1.cs)变得越来越大。例如,我有一个TabControl,每个选项卡都有一堆控件,所有代码最终都保存在Form1.cs中。如何避免这种情况?

另外,您知道处理这些问题的文章或书籍吗?

Answers:


24

看来您已经陷入了一些常见的陷阱,但是请放心,可以解决这些问题:)

首先,您需要以不同的方式看待您的应用程序,然后开始将其分解为大块。我们可以将块分割成两个方向。首先,我们可以将控制逻辑(业务规则,数据访问代码,用户权限代码以及所有这些东西)与UI代码分开。其次,我们可以将UI代码分解为大块。

因此,我们将首先进行后一部分,将UI分成多个部分。最简单的方法是拥有一个主机窗体,在该窗体上可以将用户控件与用户控件组合在一起。每个用户控件将负责表单的区域。因此,假设您的应用程序有一个用户列表,当您单击某个用户时,该用户下方的文本框将填充其详细信息。您可以让一个用户控件管理用户列表的显示,而让另一个控件管理用户详细信息的显示。

真正的窍门是如何管理控件之间的通信。您不希望表单上的30个用户控件全部随机地保持彼此之间的引用并在它们上调用方法。

因此,您可以为每个控件创建一个接口。接口包含控件将接受的操作及其引发的任何事件。考虑此应用程序时,您无需担心列表框列表选择是否更改,您对新用户已更改的事实很感兴趣。

因此,使用示例应用程序,用于托管用户列表框的控件的第一个界面将包括一个名为UserChanged的事件,该事件将用户对象传递出去。

这很棒,因为现在如果您对列表框感到厌烦,并且想要一个3d zoomy魔术眼控制,只需将其编码到相同的界面并插入:)

好的,第二部分,将UI逻辑与域逻辑分开。好吧,这是一条破旧的道路,我建议您在这里查看MVP模式。真的很简单。

每个控件现在都称为一个视图(MVP中的V),我们已经介绍了上面需要的大部分内容。在这种情况下,控件及其接口。

我们要添加的只是模型和演示者。

该模型包含管理应用程序状态的逻辑。您知道这些东西,它将进入数据库以获取用户,在添加用户时将其写入数据库,依此类推。这个想法是您可以将所有这些与其他所有事物完全隔离地进行测试。

演示者的解释有些棘手。它是一个位于模型和视图之间的类。它是由视图创建的,并且该视图使用我们前面讨论的界面将自身传递给演示者。

演示者不必具有自己的界面,但是无论如何我都喜欢创建一个。使您想要演示者做的事情变得明确。

因此,演示者将公开诸如ListOfAllUsers之类的方法,View将使用该方法来获取其用户列表,或者,您可以将AddUser方法放入View并从演示者中调用该方法。我更喜欢后者。这样,演示者便可以在需要时将用户添加到列表框中。

Presenter还具有CanEditUser之类的属性,如果可以编辑所选用户,则该属性将返回true。然后,View将在每次需要知道时进行查询。您可能需要黑色的可编辑文本,而灰色的只读文本。从技术上讲,这是针对View的决定,因为View是针对UI的,首先用户是否可编辑是针对Presenter。演示者知道是因为它与模型对话。

因此,总而言之,请使用MVP。Microsoft提供了一种称为SCSF(智能客户端软件工厂)的产品,该产品以我所描述的方式使用MVP。它也做很多其他事情。这很复杂,我不喜欢他们做所有事情的方式,但这可能会有所帮助。


8

我个人更喜欢将几个程序集之间的关注区域分开,而不是将所有内容捆绑在一起成为一个可执行文件。

通常,我更喜欢在应用程序的入口点中保留绝对少量的代码-没有业务逻辑,没有GUI代码并且没有数据访问(数据库/文件访问/网络连接/等);我通常将入口点代码(即可执行文件)限制为类似于

  • 从所有相关程序集创建和初始化各种应用程序组件
  • 配置整个应用程序所依赖的任何第三方组件(例如,用于诊断输出的Log4Net)
  • 我还可能在主函数中包含“捕获所有异常并记录堆栈跟踪”类型的代码,这将有助于记录任何未预见的严重/致命故障的情况。

至于应用程序组件本身,我通常希望在一个小型应用程序中至少有三个

  • 数据访问层(数据库连接,文件访问等)-根据应用程序使用的任何持久性/存储数据的复杂性,其中可能会有多个程序集-我可能会创建一个单独的程序集以进行数据库处理(甚至可能创建多个程序集,如果与数据库进行交互涉及复杂的事情-例如,如果您的stucx数据库设计不良,则可能需要处理代码中的数据库关系,因此编写多个模块进行插入和检索可能很有意义。

  • 逻辑层-包含所有使应用程序正常工作的决策和算法的主要“要素”。这些决定对GUI绝对一无所知(谁说有GUI?),而对数据库则一无所知(呵呵?有数据库?为什么没有文件?)。设计良好的逻辑层可以“剥离”并放到另一个应用程序中,而无需重新编译。在一个复杂的应用程序中,可能会有很多这样的逻辑程序集(因为您可能只想撕裂“片段”而不用拖拽应用程序的其余部分)

  • 表示层(即GUI);在小型应用程序中,可能只有一个带有两个对话框的“主窗体”,这些对话框都可以放入一个单独的程序集中-在较大的应用程序中,可能会有用于GUI整个功能部分的单独程序集。这里的类除了使用户交互有效外,其他的工作不多-它仅是具有一些基本输入验证,处理任何动画等的shell。任何“做某事”的事件/按钮单击都将传递给逻辑层(因此,我的表示层将严格不包含任何应用程序逻辑,但是也不会在逻辑层上放置任何GUI代码的负担-因此,任何进度条或其他奇特的东西也将位于表示组件中/ ies)

我将Presentation,Logic和Data层拆分为单独的程序集的主要理由是:我觉得最好能在没有数据库或GUI的情况下运行主要应用程序逻辑。

换一种方式; 如果我想编写另一个可执行文件,其行为与您的应用程序完全相同,但是使用命令行界面或Web界面;然后将数据库存储交换为文件存储(或者可能是其他类型的数据库),那么我可以这样做,而无需完全接触主要的应用程序逻辑-我要做的就是写一点命令行工具和另一个数据模型,然后“将它们全部插入”,我准备开始了。

你也许会想“嗯,我永远不会想要做任何的那所以它并不重要,如果我不能掉围绕这些东西” -真正的问题是一个模块化应用的标志,一个是在能够提取“块”(无需重新编译任何内容),并在其他地方重用这些块。为了编写这样的代码,通常会迫使您对设计原则进行长时间的认真思考-您需要考虑编写更多的接口,并仔细考虑各种SOLID原则的权衡取舍(在同一篇文章中行为驱动开发或TDD的方式)

有时,将这种代码与现有的整体代码块分开很麻烦,并且需要大量仔细的重构-好的,您应该能够逐步进行重构-您甚至可能会遇到程序集太多而您决定以另一种方式返回并重新将它们重新包装在一起(在相反的方向上走得太远可能会导致这些组件自身变得毫无用处)


4

根据文件夹结构,通常建议您可以。您可能需要添加资源文件夹(有时人们创建资源,以便将每组资源都按照ISO语言代码分组以支持多种语言),图像,数据库脚本,用户首选项(如果不作为资源处理),字体,外部dll,本地dll等。

添加类时的命名约定是什么?

当然,您希望将表格之外的每个类分开。我也建议每个类一个文件(尽管MS不会在为EF生成的代码中这样做)。

许多人使用有意义的简短名词复数形式(例如,客户)。一些名称应尽量接近相应数据库表的单数名称(如果在对象和表之间使用1-1映射)。

有关命名类,有许多来源,例如:.net命名约定和编程标准-最佳实践和/或STOVF-C#编码准则

怎么办,以便不是主窗体的所有代码都以Form1.cs结尾

帮助程序代码应转到一个或多个帮助程序类。GUI控件非常常见的其他代码(例如,将用户首选项应用于网格)可以从表单中删除,并添加到帮助器类中,或者通过对相关控件进行子类化并在其中创建必要的方法来实现。

由于MS Windows窗体具有事件操作性质,因此我所知道的没有什么可以帮助您从主窗体中删除代码而又不增加歧义和精力的。但是,MVVM可能是一个选择(在将来的项目中),例如,请参见:Windows窗体的MVVM


2

考虑将MVP作为选项,因为它将帮助您组织表示逻辑,这是大型业务应用程序中的所有内容。在现实生活中,应用程序逻辑大部分驻留在数据库中,因此很少有需要实际用本机代码编写业务层,而仅需要具有结构良好的表示功能。

类似于MVP的结构将导致一组演示者或控制器(如果您愿意),它们将相互协调,并且不会与UI或后面的代码混合在一起。您甚至可以在同一控制器上使用不同的UI。

最后,简单的资源组织,去耦组件和使用IoC和DI指定缺陷,以及MVP方法将为您提供构建系统的关键,该系统可以避免常见的错误和复杂性,及时交付并可以进行更改。


1

项目的结构完全取决于项目及其大小,但是您可以添加一些文件夹,例如

  • 通用(包含类,例如实用程序)
  • DataAccess(与使用sql或您使用的任何其他数据库服务器的数据访问相关的类)
  • 样式(如果您的项目中有任何CSS文件)
  • 资源(例如图像,资源文件)
  • 工作流程(与工作流程相关的类,如果有的话)

您不需要将Forms放入任何类型的文件夹中,只需相应地重命名表单即可。我的意思是说,没有人会比您自己更好的名称是它的常识。

命名约定就像如果您的班级打印“ Hello World”消息那样,则班级名称应与任务相关,而班级的适当名称应为HelloWorld.cs。

您也可以创建区域,例如

#region Hello 然后最后出来 endregion

您可以为选项卡创建类,当然可以,最后一件事是在可能的情况下重用代码,最佳实践是制作方法并在需要时再次使用它们。

书?嗯

没有书可以告诉您项目的结构,因为每个项目都是不同的,您需要通过经验来学习这些东西。

希望能有所帮助!

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.