• 基于窗体设计器的企业管理软件开发工具


    因为工作的关系,接触到企业管理软件开发平台。一套很完备的工具集,方法论和应用案例。这东西有点像软件工厂,可以根据业务需求不同,生产各种类型的软件。大部分通用的功能,比如数据的增删查改,报表,都可以预先做好,然后根据各项目业务不同,加载不同的业务模块,组装成产品。
    以我的理解,做这么一套工具集,需要很强的编程功力,至少还要有一个团队,可以分工协作,做基础模块的要保证稳定,做应用模块的,做出的程序要有很强的适应能力,可以应对各种需求的变化。

    一套完整的开发平台,应该包括
    实体设计器 可以设计业务实体,生成SQL脚本代码和类代码。
    窗体设计器  设计用户界面,一次设计,可以同时生成Desktop,Web两种界面
    业务流程设计器 设计系统流程,可适应各行业的流程需求
    部署工具  部署用户定制设计的内容

    下面以我的理解,谈谈窗体设计器的前前后后相关的内容。因为这些工具是我业余时间折腾的,和公司的平台和技术毫不相关,所以我能放心的与你分享我的设计思路。
    1  首先要有一个窗体设计器。这东东,到现在为止,还是个很宝贵的工具,网上(google)几乎找不到可以拿来用的,有一些DEMO演示,但不完善,还要做很多工作。
    如果你知道rehost技术,还知道SharpDevelop这本书,可以找到窗体设计器的源码。还有这篇文章,《用.NET Framework 2.0创建 Form设计器》,都可以解决窗体设计器的源码问题。
    CodeProject上面也有几个不错的例子,可以直接拿来就用的。
    2  找到了窗体设计器的源码,接下来做的工作就是分析它的机制,要满足几条才能应用
    1)序列化机制 XML格式是最好的存储格式,因为XML可以跨平台,被任何语言和工具解析,将来被移植的可能性大,XML格式可以被各种小工具和小应用程序解析,比如在实际应用中要判断窗体对应的表是否存在,可以直接读取相应的XML片段,判断即可。
    CodeProject上面有一个很好的窗体设计器,就是因为它把窗体序列化为二进制格式,解析起来相当不方便,只好忍痛放弃。
    2)可支持扩展。比如需要在设计器中加载第三方的控件,可以通过增加一行配置就保证运行正常。
    image

    如图,Windows Forms工具箱加载.NET提供的基础控件,Flex Forms工具箱加载自定义的控件。
    为什么要加载自定义控件呢?为了平台的方便。比如,如果用TextBox接受用户的输入,输入本月购买直接物料的数量,在保存窗体文件时,需要检查输入的类型是数值类型,这样的检查需要很多重复的代码。如果把TextBox换成IntegerBox,这个控件只接受整型的数值,否则会报错。这样,检查用户输入的代码就可以移到窗体设计器的运行时码中,减少代码重复。

    3 于是,拖拖拉拉设计好窗体,点击保存,问题又来了,如何保存呢?
    1)直接保存到电脑本地文件,这样可以随时修改。因为要做一系列的窗体,比如一个采购审批系统,要有采购申请单,部门经理审核单,财务经理审核单。当这些窗体多了以后,需要规范的管理起来,不能在电脑上到处乱放。于是,在指定的目录,放相同模块的窗体文件。
    好处很明显,查找容易,修改也容易。缺点是文件容易被篡改,不安全
    2)把文件上载到服务器。点击保存按钮时,把当前的窗体文件上传到服务器的指定的目录下。
    3)把文件保存到数据库中。这个是目前我采用的方案,直接放到数据库中,安全是没有问题。但是每次需要读取数据,解析,还原成XML窗体文件。当窗体的控件很多时,运行和设计都很慢
    4)把文件编译成Assembly文件,直接放到当前程序集目录下。这个方案可以解决文本文件不安全的问题,也可以解决速度问题,因为是在本机,可以很方便的读取,而且是assembly格式,不容易被破坏。
    保存的时候,也有讲究。不能用名字,因为名字可能会重复。用不会重复的GUID,但是不容易识别,还要配合名字,方便用户查找。

    4  窗体文件被保存后,如何被快速检索呢?
    做到这一步,需要开始涉及业务方面的处理。首先,需要一个管理工具,按照系统的划分层次,可以建立应用程序(Application),建立模块(Module),然后把设计的窗体文件划分到具体的类别当中。
    比如,设计一个采购系统,命名为Purchase Management,再建立几个模块,申请模块和审批模块,还有涉及到库存,也要设计好。
    当上传窗体文件的时候,就需要按照当前的窗体的作用,放到选定的模块中。
    于是,可以按照模块来检索窗体文件,根据需要,做相应的修改或调整。
    为了方便,也可按照名字,搜索窗体,找到后,直接在设计器中打开。
    虽然窗体文件是用GUID来识别的,但是用户很少能记住这一长串的字母,很少去用ID来查找窗体。

    5  窗体设计好了,也保存成功,现在需要一个窗体运行容器(Container,Runntime),可以容纳窗体运行。在容器启动时,需要加载一系统的服务,以保证窗体的运行;容器同时也提供窗体的测试环境,把设计器设计好的文件丢到容器中跑一下,看看有什么问题,以方便诊断。
    image

    如图,可以直接打开窗体设计完成后的XML文件,看看运行的效果;也可以连到服务器,打开服务器中的窗体文件,作出适当的调整。这个工具集窗体测试,诊断分析于一体,相当的好用。

    6 做一个应用界面,加载必要的服务,根据服务器中的应用程序(Application)和模块(Module),建立导航界面,引导用户进入相应的模块。用户设计的一般是分散的应有,很少考虑整个系统的完整性,同时,用户设计的窗体也不容易加载扩展插件,比如业务插件,流程插件。需要自己写一个容器,把用户设计的界面,集成到一起,同时提供一些基础的服务。
    到这一步,一个基于窗体设计器的应用软件就已经设计完成,所有的过程不需要编码。

    7  数据如何被存储到数据库中,又是如何被查询出来?
    在设计界面的时候,界面上的控件就已经和数据库中的表进行了绑定。
    image
    在新建一个数据输入类型的窗体,会有一个DataTable属性,用于指定该窗体对应的数据库表
    在窗体中每个需要输入数据,并进行保存的控件,也有一个DataColumn属性,于是指定数据的列
    还有一个DataType属性,把用户输入的内容,输化为DataType类型的数据,存到DataColumn指定的数据列中。
    image 
    这些设计都以可视化的方式完成,减少出错。如下图,直接获取一个表的字段信息,用于填充窗体控件
    image

    如果是查询窗体,也可以用SQL智能的查询分析器,帮助用户快速构建查询结果 image
    用户可以手写SQL语句,也可以点击查询按钮,用查询分析器来写SQL。
    这里有个疑问,一直没搞懂。用ICSharpCode.TextEditor.dll作语法高亮编辑器,无论文件是否超过一屏,它都会出现横向滚动条,很不美观,在网上找了很久也搞不定。我的代码生成器也是这样。
    如果一个SQL语句只有几个字符,它也显示横向的滚动条,看着很不舒服。
    在检索窗体的时候,会检查这个窗体是否有数据,如果有数据,会加载数据。如果是新建一个窗体,比如新建一个采购申请单,则不加载数据。

    8  业务插件如何加载,系统如何扩展?
    这是同一个问题。用标准的assembly格式,写好需要被调用的方法。在窗体运行之前,会加载一系列的服务,这个服务包含加载配置文件中指定的类库。用简单的语法,在需要调用自定义逻辑的地方,指定方法名和参数,运行时引擎分析这个参数(是个字符串),解析成反射的方法调用语法,调用指定的类库中的方法。为了方便,系统会预先写好一些常用的类库,比如时间处理,序列号处理。
    如果用户需要扩展系统,把assembly放到指定的目录下,在配置文件中指定需要加载的程序集,然后只管在需要的地方调用,引擎会处理好怎么去找程序集,如何反射到方法并调用。
    比如,我为了验证这种方法的可行性,故意写了个数据库备份工具
    image 
    界面布局有点乱。取到界面上的用户输入的Server,UID,Password的值,传到Backup按钮的点击事件中,该事件运用反射,调用我写好的类库,数据库备份功能。
    public void Backup(string server, string database, string uid,string password)
       {
    SQLDMO.SQLServer svr = new SQLDMO.SQLServerClass();
    svr.Connect(ServerName, UserName, Password);
    SQLDMO.Backup bak = new SQLDMO.BackupClass();
    bak.Action = 0;
    bak.Initialize = true;
    SQLDMO.BackupSink_PercentCompleteEventHandler pceh = new SQLDMO.BackupSink_PercentCompleteEventHandler(Step);
    bak.PercentComplete += pceh;
    bak.Files = strFileName;
    bak.Database = strDbName;
    bak.SQLBackup(svr);

    }

    还有一些细节没有考虑到,比如数据库的表如何设计,表与窗体如何关联,如何验证窗体,如何把窗体与工作流程绑定。有时间的时候再补充。
    搞这个东东还是很辛苦的,也不见得有什么成效。真正做起项目来,客户需求一改再改,界面换了一次又一次,如果都用平台来做,估计会累死。我折腾过几次,也没有大的成效,技术的提升只是额外的收获。有理解的不对的地方,请各位多多指教。

  • 相关阅读:
    委托(2).net 1.x中的委托
    委托(1)认识委托
    克隆对象的几种方法
    常用的去重和排序
    为更好地设计数据库,重新整理sql server数据类型
    对于数据库中表示状态或类型字段表示方法的思考
    string to byte[]
    json序列化时datetime的处理方法
    dll版本冲突的解决方法
    .net中的序列化
  • 原文地址:https://www.cnblogs.com/JamesLi2015/p/1666796.html
Copyright © 2020-2023  润新知