在上位机开发领域中,C#与C++两种语言是应用最多的两种开发语言,在C++语言中,与之搭配的前端框架通常以QT最为常用,而C#语言中,与之搭配的前端框架是Winform和WPF两种框架。今天我们主要讨论一下C#和WPF这一对组合在上位机开发过程中的实际应用。
一、模块化概念
开发一套完善的软件,离不开良好的架构,而说到架构,在C#中,Prism框架与WPF的配合可谓大大提高了开发效率,原因如下:Prism框架中有IOC容器(分别是unity和dryioc),IOC容器负责管理类的生命周期;另外,Prism框架的WPF版本还有区域管理器(RegionManager)、事件聚合器(EventAggregator),对话框服务(DialogService)、适配器(Adapter)、模块管理器(ModuleManager)等。
除了模块管理器(IModule接口),其他几个重要的管理器都是为了更方便实现界面呈现及业务逻辑开发,那么模块管理器的功能是什么呢?程序员往往会将一个大型的软件项目拆分成小项目(模块),比如上位机系统中会接入各种硬件(工业相机、PLC、数据采集器、扫码枪、控制卡等),良好的软件架构思路是将同一种类型的硬件抽象成一个硬件抽象类,然后,不同型号的硬件与继承这个抽象基类,实现各自硬件的业务逻辑(加载硬件、打开硬件、使用硬件、关闭硬件),要实现这些开发,Prism的模块就派上用场了。也就是将硬件进行模块化,由Prism框架去实现及统一管理。
当然,除了上述的例子,软件的基础库,软件的业务逻辑,同样可以拆成不同的模块,最后由Prism框架统一管理。
二、反应式概念
C#语言为我们提供了一个IObservable接口,也就是设计模式中的观察者模式在C#语言中的具体实现。ReactiveUI框架对此接口进行了扩展,使之变得易用。
在传统的软件开发中,我们对某个属性发生变化后要进行下一步的相应处理时,会主动对判断这个属性的值,然后实现相应的代码逻辑。而在观察者模式下,我们会写一个观察者,由这个观察者去"实时"观察这个属性,一旦观察到属性值发生了改变,会抛出一个通知。
那么,通知谁呢?
谁去订阅了这个观察者,其回调函数都会被触发一次调用,从而达到一个目的,即被观察的那个属性发生改变后会执行事先写好的"某一段代码逻辑"。
这样的开发模式在写上位机软件时非常可靠和易用,因为上位机可能会实时监测下位机的某些参数变化,一旦硬件参数发生变化,软件要相应给出动作(做出反应),这种反应,我们称为反应式编程。
三、软件架构
良好的架构,可以帮助开发人员提高开发效率,减少bug的发生,增强系统的稳定性。我们可以将一个上位机系统分成如下几个方面:
第一是具有通用性的基础类库,这一些类与具体的业务逻辑无关,只帮助处理业务过程中的数据,通常是一些帮助类,或者语言包,本地设置等等;
第二、是硬件模块,上位机开发离不开硬件的接入,而不同的上位机系统,其接入的硬件也是五花入门,比如MES系统,可能最常见的硬件是PLC、扫码枪;而控制系统,则控制卡与各种被控设备的信息反馈最为常见;AOI,AXI等工业视觉检测方面,则接入的硬件除了PLC和控制卡,还有工业相机,光机,光源等等;或者医学方机的上位机,包含了更多的非标设备。
如此多的硬件,如何有序的接入到上位机呢?
答案是,最好将同一种类型的硬件抽象成一个基类,通过接口、抽象类、继承等方面的编程手段,为每一种不同厂家或不同型号的硬件创建一个项目,将这些项目看成是一个个独立的模块,像小孩子玩积木游戏一般,将硬件"堆积"到上位机中,一旦某个型号的硬件想被替换,直接将新硬件的模块加载到上位机即可。
第三,是数据库模块。由于上位机系统运行过程中需要处理大量的数据,其处理结果需要持久化,一般采用文件或数据库的形式进行保存。而数据库的操作就可以单独形成一个模块,这个模块包含抽象类模块和具体的数据库操作类模块,因为最终要保存的数据库可能是mysql、oracle、mssql等不同的数据库,所以最好的方式是为不同类型的数据库的增删改查等操作开发各自的模块,以便管理和替换。
第四,是业务逻辑模块。这一类型的模块会随着不同行业的上位机功能需求,模块的多少会有所不同。尽量将复杂的业务逻辑拆分成独立的小型业务模块,模块与模块之间采用接口通讯,这样做的好处是:减少代码间的耦合程度,尽量开发一些职责单一的类,达到具有良好扩展性的代码架构。
四、详细设计
在聊完了大致的软件架构,我们来谈谈具体的模块设计。利用vs2022开发软件,一个模块就是一个项目,有的项目是类库,有的是用户控件,有的是窗体,还有的是C++项目,具体的开发如下所示:
为了更清晰明了每个项目的含义,我们制定一套项目(模块)的命名规则:公司名+架构分类名+模块名,比如Company.Application.Main,表示应用层的主模块。
第一、程序入口项目
Company.Application.Shell,这是上位机系统的入口,其实是一个窗体,启动时加载的第一个窗体,其内容由主模块进行填充。
第二、应用层模块
Company.Application.Main,这是上位机的主模块,由Prism框架的区域管理器将此模块导航到Shell窗体中。
Company.Application.Config,这是上位机的系统配置模块。
Company.Application.Login,这是上位机的用户登录模块。
Company.Application.Initialize,这是上位机的硬件加载模块,当然一些软件方面的加载也可放其中。
Company.Application.Share,这是上位机的共享模块,此模块的作用非常重要,负责各个模块的数据通讯。
Company.Application.Menu,这是上位机的菜单模块,负责菜单生成或管理。
Company.Application.More,这个表示其它模块,根据上位机功能而定。
第三、核心层模块
Company.Core,这是上位机的核心模块,与主业务无关,提供一些基础帮助类,全局类等,比如Json文件的序列化与反序列化,对话框管理器、缓存管理、本地语言包管理、各种helper类型等。
Company.Logger,这是上位机的日志模块,可以采用NLog或Log4net等常用组件,此模块也与主业务无关,被其它所有模块所引用,负责打印程序错误信息或调试信息。
Company.UI,这是上位机关于UI的资源模块,如WPF的模板样式定义、程序所引用的图标、图像、字体库、语言包、转换器,用户控件等。
第四、硬件层模块
Company.Hardware.Camera,这是上位机的工业相机抽象类模块,负责定义一台相机的功能,定义相机的配置参数和操作业务流程(如打开相机、使用相机、关闭相机)。
Company.Hardware.Camera.HIK,表示一台海康工业相机,它继承了相机抽象类,并实现其自身的API调用。
Company.Hardware.Camera.Other,表示其它工业相机,other要换成具体的相机名称,说明可能无限扩展其它厂家或其它型号的相机。
Company.Hardware.ControlCard,这是上位机的控制卡抽象基类,负责定义一张控制卡的功能,但不实现具体的操作流程,只规定操作接口,具体操作由子类实现。
Company.Hardware.ControlCard.DMC2610,比如雷赛运动控制卡DMC2610。
Company.Hardware.ControlCard.ADTech632XE,比如众为兴运动控制卡632XE。
其它的硬件都可以采用上述的命名方式去扩展。
第五、数据库模块
Company.Database.Core,这个模块定义了数据库的操作接口,仓储层的抽象类型 等。
Company.Database.EF,这是采用EF框架去对数据库进行增删改查的模块,其中的类型都继承于Core中的抽象类。
接下来,用一张结构图,演示详细的上位机架构
上位机开发架构设计高清大图链接地址 :
上位机课程思维导图
https://www.processon.com/view/link/64a10419111c1d7d8a19db04
重庆教主的VIP课程
WPF中关于Prism框架的学习课程
https://edu.51cto.com/course/33880.html
C#+WPF上位机开发课程(模块化与反应式编程)
https://edu.51cto.com/course/34143.html
C#+WPF项目实战MVVM模式开发《超市管理系统》
https://edu.51cto.com/course/33794.html
作者:重庆教主