WinForm应用实战开发指南 - 如何完成工作流模块的业务表单开发?

发布时间:2026/8/18 13:18:07
WinForm应用实战开发指南 - 如何完成工作流模块的业务表单开发? 在我们开发工作流的时候往往需要涉及到具体业务表单信息的编辑有些是采用动态编辑的有些则是在开发过程中处理的各有各的优点动态编辑的则方便维护各种各样的表单但是数据的绑定及处理则比较麻烦而自定义开发的则数据弹性很大方便修改调整。本篇随笔基于表单的开发设计过程介绍在工作流中如何新增一个业务表单以便快速的实现审批业务的上线处理。PS给大家推荐这个WinForm应用界面开发组件——DevExpress WinForms它能完美构建流畅、美观且易于使用的应用程序无论是Office风格的界面还是分析处理大批量的业务数据它都能轻松胜任DevExpress新旧版本帮助文档获取可点击这篇文章查看——《界面控件DevExpress v26.1帮助文档大全CHM版本》业务表单的基类继承首先我们来了解一下业务表单的对应关系一般创建一个业务流程处理都需要有一个具体的创建业务表单的界面以及一个查看处理表单的界面。为了方便我们尽可能减少代码编写我们需要把大多数的逻辑处理放在基类实现这样我们在新增一个业务表单的时候就可以减少很多代码编写及维护了。如对于FrmAddApply类定义如下我们定义一些抽象接口用于下面的业务表单实现/// summary /// 创建申请单的窗体基类 /// /summary public partial class FrmAddApply : BaseForm { /// summary /// 表单ID /// /summary public string FormID { get; set; } /// summary /// 申请单ID /// /summary public string ApplyId { get; set; } public FrmAddApply() { InitializeComponent(); } /// summary /// 显示数据的函数(子类必须实现 /// /summary public virtual void DisplayData() { } /// summary /// 实现控件输入检查的函数(子类必须实现 /// /summary /// returns/returns public virtual bool CheckInput() { return true; } /// summary /// 编辑状态下的数据保存(子类必须实现 /// /summary /// returns/returns public virtual bool SaveUpdated() { return true; } /// summary /// 新增状态下的数据保存(子类必须实现 /// /summary /// returns/returns public virtual bool SaveAddNew() { return true; } ...................这样我们创建一个新的业务表单只需要利用代码生成工具生成所需要的各层框架代码然后再生成Winform窗体代码复制部分界面处理代码过来这个业务表单的子类即可。下面是一个请假申请的业务表单设计如下所示。我们看到这个表单可以使用代码生成工具Database2Sharp快速生成后进行一定调整的而这个编辑表单的界面我们只需要使用自动生成的部分代码即可。相关代码只需要复制上面的新增、更新、显示数据的代码即可。对于查看申请单的基类FrmViewApply类我们更加简单我们需要把它的自定义界面控件加载出来即可。下面是查看申请单的基类封装了相关的处理逻辑。/// summary /// 本窗体是通用的查看申请单界面基类。 /// 为减少开发相关页面的工作量只需要创建一个新窗体并继承本窗体然后在子窗体Form_Load函数里面初始化对应的申请单显示控件即可。 /// /summary public partial class FrmViewApply : BaseDock { /// summary /// 申请单ID /// /summary public string ApplyId { get; set; } /// summary /// 申请单自定义控件 /// /summary public BaseUserControl ApplyControl { get; set; } /// summary /// 默认构造函数 /// /summary public FrmViewApply() { InitializeComponent(); } private void FrmViewApply_Load(object sender, EventArgs e) { if (!this.DesignMode) { InitToolBar(); } } /// summary /// 初始化申请单控件 /// /summary protected virtual void InitApplyControl(BaseUserControl control) { if (control ! null) { this.ApplyControl control; this.ApplyControl.Dock DockStyle.Fill; this.Controls.Add(control); } } /// summary /// 打印申请单控件内容(默认调用窗体打印 /// /summary protected virtual void PrintApplyControl() { if(this.ApplyControl ! null) { PrintFormHelper.Print(this.ApplyControl, false); } } /// summary /// 表单另存为 /// /summary protected virtual void ApplySaveAs() { } /// summary /// 初始化工具栏的按钮和状态 /// /summary protected virtual void InitToolBar() { ................//基类实现控制什么时候该做什么审批处理以及一些常见按钮 } .................查看请假申请单的窗口就是继承这个FrmViewApply即可如下所示。/// summary /// 查看请假申请单的窗体 /// /summary public partial class FrmViewLeave : FrmViewApply { private LeaveControl control null; public FrmViewLeave() { InitializeComponent(); } private void FrmViewLeave_Load(object sender, EventArgs e) { //初始化控件并展示在基类窗体里面 control new LeaveControl(); control.ApplyId this.ApplyId; control.DisplayData(); base.InitApplyControl(control); } }这个就是全部的窗体源码了主要的内容我们看到是在LeaveControl这个用户控件类里面的了而这个控件主要就是上面编辑请假申请单的界面设计并复制相关的显示数据代码即可。相关界面代码如下所示。/// summary /// 查看请假申请单的内容显示控件 /// /summary public partial class LeaveControl : BaseUserControl { /// summary /// 申请单ID /// /summary public string ApplyId { get; set; } public LeaveControl() { InitializeComponent(); SetReadOnly(); } /// summary /// 设置整个窗体布局为只读并设置只读的背景颜色 /// /summary private void SetReadOnly() { this.layoutControl1.OptionsView.IsReadOnly DevExpress.Utils.DefaultBoolean.True; this.layoutControl1.Appearance.ControlReadOnly.BackColor Color.SeaShell; } private void LeaveControl_Load(object sender, EventArgs e) { this.applyInfoControl1.ApplyId this.ApplyId; this.applyInfoControl1.BindData(); } /// summary /// 初始化数据字典 /// /summary private void InitDictItem() { //初始化代码 } /// summary /// 数据显示的函数 /// /summary public void DisplayData() { InitDictItem();//数据字典加载公用 //由于申请单一般是用申请表单入口而非业务数据表因此只能传入ApplyId获取信息 if (!string.IsNullOrEmpty(ApplyId)) { .................... }通过上面定义的对应表单的窗体基类可以减少我们重复编码的需要我们只需要利用最有效率的生成界面然后复制代码后调整即可快速生成我们所需要的不同表单界面。每个表单我们放在一个目录上这样我们就可以很好管理它们了。业务表单的动态展示处理上面介绍了业务表单的填写、查看两个不同的窗口我们在申请单的审批界面里面统一显示不同的表单以及创建不同的业务表单界面这种动态的处理可以实现不同业务表单的创建及显示界面。如我的审批工作中表单的显示界面如下所示查看具体表单后可以动态展示不同的业务窗口界面。另外我们在创建业务表单的时候根据数据库的配置信息动态展示所有可以展示的创建入口单击相关的按钮可以动态调用创建对应的表单界面。创建流程业务表单的入口如下所示。在我的审批工作界面动态创建对应的查看表单窗体代码如下所示。/// summary /// 分页控件编辑项操作 /// /summary private void winGridViewPager1_OnEditSelected(object sender, EventArgs e) { //获取记录ID和表单ID string ID this.winGridViewPager1.gridView1.GetFocusedRowCellDisplayText(ID); string FormId string.Concat(this.winGridViewPager1.gridView1.GetFocusedRowCellValue(FormId)); if (!string.IsNullOrEmpty(ID) !string.IsNullOrEmpty(FormId)) { var formInfo BLLFactoryBLL.Form.Instance.FindByID(FormId); if (formInfo ! null !string.IsNullOrEmpty(formInfo.ApplyWin2)) { try { //根据配置的查看窗体动态构建查看申请单对象 FrmViewApply dlg Assembly.GetExecutingAssembly().CreateInstance(formInfo.ApplyWin2) as FrmViewApply; if (dlg ! null) { dlg.ApplyId ID; dlg.OnDataSaved new EventHandler(dlg_OnDataSaved); if (DialogResult.OK dlg.ShowDialog()) { BindData(); } } } catch (Exception ex) { LogHelper.Error(ex); MessageDxUtil.ShowError(ex.Message); } } } }这个代码替代了需要手动创建不同对象的处理。var dlg new FrmViewAssignWork(); dlg.ApplyId ID; dlg.OnDataSaved new EventHandler(dlg_OnDataSaved); if (DialogResult.OK dlg.ShowDialog()) { BindData(); }同理对于创建编辑界面我们也可以同样的方法动态创建相关的编辑表单界面如下代码所示。本文转载自博客园 - 伍华聪