大型企业往往有一个或几个核心系统, 为了保证核心系统的稳定, 很少直接在核心系统内部添加新功能, 而是采用外挂形式增加新功能. 在传统企业内部, 这些外挂系统往往是一些Windows桌面系统, 这些外挂系统从源码角度看, 都很类似, 有着相同的用户登录验证, 相同的权限管控方式,相同的后台数据库, 但因为各种原因, 它们并没没有被很好地规划, 比如缺少统一的UI设计,逻辑类似但项目代码没有被很好的组织, 相同的代码不断地被复制粘贴, 维护成本越来越高.
这里给出一个解决方案: 建立桌面版的小程序体系, 示意图见下.
原先是在核心系统中直接打开某个外挂系统, 将来转变为先打开小程序容器程序, 并由小程序容器动态加载这个外挂模块.
改造内容:
1. 把各个外挂系统通用功能移到小程序容器系统中, 比如登录和权限验证等.
2.将外挂系统退化成外挂功能模块, 为了减少改造成本, 这些外挂模块仍以C#项目形式存在, 只是转换成dll类库系统. 备注:C#的dll项目是可以包含Form窗体的.
改造收益:
1. 统一了UI风格, 更好的使用体验.
2.将多个源码solution合并到一个源码solution中, 代码复用性会更好, 源码管理成本会大大降低,将来功能升级也更容易.
实现方式:
采用著名的开源WinForm控件 DockPanelSuite, 使用DockPanel作为外挂模块的容器, 改造难度非常小. 下面简单介绍具体做法.
外挂项目:
⒈外挂项目转成dll类库项目形态, 其实也可以是独立的Exe程序, 但如果是Exe的化, 容易绕过容器程序.
2. 外挂项目增加Dock panel suite 引用
3. 对于外挂项目主界面或需要被核心系统直接调出的界面, 将其基类从 Form 转成 DockPanelSuite 中的 DockContent 类, DockContent 类其实也是 Form 类的子类, 最好是定制化一个统一的 DockContent 类, 比如 DockableForm, 统一所有外挂模块的样式.
4. 下面是 DockContent 类的一些扩展属性和方法
(1) AllowEndUserDocking 属性: 是否允许最终用户调整 Dock 方式
(2) AllowEndUserNestedDocking 属性: 是否允许最终用户来嵌套Dock
(3) TabText 属性 : 设置 Tab 页签的 header 文本
(4) DockAreas 属性: 子窗体可以被dock到的位置, 比如 上/下/左/右等
(5) HideOnClose 属性, 设置为 True 时, 关闭子窗体其实仅仅是隐藏
(6) CloseButton, bool 属性, 是否可以关闭 tab 页签
(7) CloseButtonVisible 属性, pane 上的 close button 是否可见.
(8) DockHandler 属性, 其实可以将 DockContent 类认为是 Form + DockHandler, 也就是 DockContent 扩展的属性和方法都是来源于 DockHandler 类
(9) Show() 方法, 通过该方法, 可以将子窗体 dock 到父窗体的 DockPanel 控件上, 可以设置 dock 过去的位置, 上下左右等等.
容器项目:
1. 将主窗体 IsMdiContainer 属性设置为 true. DockPanelSuite 底层机制和传统的 MDI 应用类似, 所以 MDI 应用的一些方式, 也适用于dockPanel 容器窗体, 比如 mainForm.MdiChildren, mainForm.ActiveMdiChild 等.
2. 增加一个 dock panel 控件
3. 设置 dockPanel 组件的一些重要属性
(1) DocumentStyle 属性,
DockingSdi: 当只有一个页签时候, 不显示该页签的header.
DockingMdi, 默认的mdi 模式,
SystemMdi: 不推荐使用, 这种方式下最大程度地模拟传统的MDI应用, , 很多处理机制和 dockPanel 其他模式不同.
(2) ShowDocumentIcon, 页签是否显示图标
(3) DocumentTabStripLocation, top/buttom, 页签实现在上方还是下方
(4) DocArea, 只读属性, 真正用于装载子窗体的区域, 如果太小, 子窗体可能显示不全.
(5) Documents 属性, 所有子窗体的清单.