在Winform界面中窗体我们一般使用多文档进行展示,也就是类似一般的选项卡的方式可以加载多个窗体界面。一般来说,我们如果打开新的窗体,给窗体传递参数是很容易的事情,但是在框架层面,一般的窗体是通过动态创建的,一般传入窗体的类型,在多文档集合里面判断,如果存在则激活,如果不存在则创建的方式,所以我们传递参数会碰到一些问题。本文即使介绍如何在这种方式下,给窗体对象传递参数,从而实现相应的数据处理功能。
不管是主体界面中,左侧包含树形列表,还是顶部包含工具栏的情况,都可能涉及打开窗体的时候,传递一些初始化参数,方便窗体的更新显示的情况,这种的处理相对直接传值的方式需要复杂一点,我们可以通过接口、事件的方式进行处理,下面我来介绍一下整个实现的方式。
1、多文档窗体的构建或者激活
在我的Winform开发框架里面,我们加载多文档窗体的时候,都是统一采用一种方式来进行构建不存在或者激活已有窗体的,代码如下所示。
private void tool_Purchase_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { ChildWinManagement.LoadMdiForm(this, typeof(FrmPurchase)); } private void tool_TakeOut_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { ChildWinManagement.LoadMdiForm(this, typeof(FrmTakeOut)); } private void tool_StockSearch_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { ChildWinManagement.LoadMdiForm(this, typeof(FrmStockSearch)); }
而这个LoadMdiForm的函数,主要判断多文档集合里面是否有对应的对象,没有这创建,有则激活显示即可,代码如下所示。
/// <summary> /// 唯一加载某个类型的窗体,如果存在则显示,否则创建。 /// </summary> /// <param name="mainDialog">主窗体对象</param> /// <param name="formType">待显示的窗体类型</param> /// <param name="json">传递的参数内容,自定义Json格式</param> /// <returns></returns> public static Form LoadMdiForm(Form mainDialog, Type formType, string json) { bool bFound = false; Form tableForm = null; foreach (Form form in mainDialog.MdiChildren) { if (form.GetType() == formType) { bFound = true; tableForm = form; break; } } if (!bFound) { tableForm = (Form) Activator.CreateInstance(formType); tableForm.MdiParent = mainDialog; tableForm.Show(); } tableForm.BringToFront(); tableForm.Activate(); return tableForm; }
这种方式构建的多文档界面如下所示。
2、多文档窗体传参数的实现处理
首先,为了实现这个方式,我们需要先创建一个接口,是我们窗体界面的基类,实现这个接口,然后在加载的时候,转换为对应的接口处理就可以了,具体接口代码如下所示。
/// <summary> /// 使用ChildWinManagement辅助类处理多文档加载的窗体,在构建或激活后,触发一个通知窗体的事件,方便传递相关参数到目标窗体。 /// 为了更加通用的处理,传递的参数使用JSON定义格式的字符串。 /// </summary> public interface ILoadFormActived { /// <summary> /// 窗体激活的事件处理 /// </summary> /// <param name="json">传递的参数内容,自定义JSON格式</param> void OnLoadFormActived(string json); }
这里参数为了通用,我们定义为字符串的JSON内容,方便实现更加强大的参数处理。
修改好这些,我们需要在基类窗体 BaseForm 实现这个增加的接口,如下所示。
/// <summary> /// 常规界面基类 /// </summary> public partial class BaseForm : XtraForm, IFunction, ILoadFormActived
实现这个接口很容易,为了更加方便业务窗体(继承自基类窗体BaseForm),我们提供一个事件进行处理,具体代码如下所示。
/// <summary> /// 常规界面基类 /// </summary> public partial class BaseForm : DevExpress.XtraEditors.XtraForm, IFunction, ILoadFormActived { /// <summary> /// 定义一个窗体激活后的处理委托类型 /// </summary> /// <param name="json"></param> public delegate void FormActiveHandler(string json); /// <summary> /// 使用ChildWinManagement辅助类处理多文档加载的窗体,在构建或激活后,触发一个通知窗体的事件,方便传递相关参数到目标窗体。 /// 为了更加通用的处理,传递的参数使用JSON定义格式的字符串。 /// </summary> public event FormActiveHandler LoadFormActived;
同时,我们实现接口,就是直接调用事件就可以了,具体代码如下所示。
/// <summary> /// 窗体激活的事件处理 /// </summary> /// <param name="json">传递的参数内容,自定义JSON格式</param> public virtual void OnLoadFormActived(string json) { //默认什么也没做 //如果需要处理传参数,则在这里处理参数Json即可 if (LoadFormActived != null) { LoadFormActived(json); } }
这样我们就完成了基类窗体的处理了,前面我们介绍了动态构建加载窗体的时候,是使用了LoadMdiForm的函数,既然我们的接口实现了上面的ILoadFormActived接口,那么我们动态创建或者激活窗体的时候,那么就使用这个接口进行处理一下,以便实现对应事件的处理操作了。因此我们的窗体加载函数修改代码,如下所示。
/// <summary> /// 唯一加载某个类型的窗体,如果存在则显示,否则创建。 /// </summary> /// <param name="mainDialog">主窗体对象</param> /// <param name="formType">待显示的窗体类型</param> /// <param name="json">传递的参数内容,自定义Json格式</param> /// <returns></returns> public static Form LoadMdiForm(Form mainDialog, Type formType, string json) { bool bFound = false; Form tableForm = null; foreach (Form form in mainDialog.MdiChildren) { if (form.GetType() == formType) { bFound = true; tableForm = form; break; } } if (!bFound) { tableForm = (Form) Activator.CreateInstance(formType); tableForm.MdiParent = mainDialog; tableForm.Show(); } //窗体激活的时候,传递对应的参数信息 ILoadFormActived formActived = tableForm as ILoadFormActived; if (formActived != null) { formActived.OnLoadFormActived(json); } tableForm.BringToFront(); tableForm.Activate(); return tableForm; }
还记得我们前面打开一个多文档窗体的代码,就是利用这个接口进行创建或者激活指定类型的窗体的,如下所示。
ChildWinManagement.LoadMdiForm(this, typeof(FrmItemDetail));
那么我们增加了新的函数参数Json后,我们如果需要传递一个指定的参数给对应的窗体,那么就修改下调用即可。例如下面,为了测试,我传入一个动态构建的类信息,然后转换为Json字符串信息给接收窗体,并进行加载窗体。
//使用自定义参数调用 var obj = new { ItemNo = "123456789", ItemName = "测试名称" }; var param = JsonConvert.SerializeObject(obj, Formatting.Indented); ChildWinManagement.LoadMdiForm(this, typeof(FrmItemDetail), param);
前面我们介绍了基类窗体,已经实现定义了一个事件,并对这些通知的接口进行处理,具体如下所示。
那么我们前面加载的 FrmItemDetail 需要做哪些工作呢,就是实现对事件的处理即可,如下所示。
这样我们就能够通过实现对应的事件,把整个通知事件的处理处理完毕了,我们来看看最终的界面效果,如下所示,接收到的窗体事件后,会弹出一个提示对话框在右下角了。
当然实际上我们可以做的更多,如可以传递一些具体的信息,让它在界面上进行显示。
如其中一个客户基于我的Winform开发框架基础上进行的参数传递案例界面如下所示。
本文只是对其中在框架层面对不同多文档窗体的传值进行的一个研究探索和实现,其中的理念是基于常用的接口和事件驱动的方式进行处理,以期达到方便、高效的目的,如果您有更好的建议,也希望多多交流。