事件的使用案列
一、案例背景
在写一个询价报价的Winfrom程序时,程序首页FORM(form名为FrmEnquiry)显示的询价记录和报价记录,
询价记录如下图:
在用户点击新增询价记录后弹出询价记录编辑FORM(form名为FrmEnquiryEdit),界面如下图:
案例需求:用户在编辑页面(FrmEnquiryEdit)中编辑完询价记录后在点击保存新增询价记录按钮后编辑界面(FrmEnquiryEdit)需要通知主界面更新显示出刚刚新增询价记录。
应用自定义事件,在用户点击保存新增询价记录按钮后触发事件通知主界面更新 以实现案例需求。代码实现步骤如下:
1、 首先定义一个用于在事件中传递数据用的事件数据类,代码如下:
public class EqDocumentSavedEventArgs : EventArgs
{
private EnquiryDocument _enquiryDocument;
/// <summary>
/// 编辑页面使用该属性传递新增编辑完成并保存后的询价记录
/// </summary>
public EnquiryDocument EnquiryDocument { get => _enquiryDocument; }
public EqDocumentSavedEventArgs(EnquiryDocument enquiry)
{
_enquiryDocument = enquiry;
}
}
注:其中EnquiryDocument为我需要通过事件传递的询价记录实体类
2、 定义一个事件的委托,代码如下:
public delegate void EqDocumentsChangedEventHandler(object sender, EqDocumentSavedEventArgs e);
委托也是一个类,可以定义在命名空间中,跟其他类同级,案例代码层次结构如下:
namespace xunjia1.Views
{
public delegate void EqDocumentsChangedEventHandler(object sender, EqDocumentSavedEventArgs e);
public partial class FrmEnquiry : DevExpress.XtraEditors.XtraForm
{
… …
}
public class EqDocumentSavedEventArgs : EventArgs
{
… …
}
… …
}
3、 在编辑询价记录界面(FrmEnquiryEdit)中用2步中定义的委托声明事件,代码及层次结构如下:
namespace xunjia1.Views
{
public partial class FrmEnquiryEdit : DevExpress.XtraEditors.XtraForm
{
… …
public event EqDocumentsChangedEventHandler EqDocumentSaved;
… …
}
}
4、 在主页面(FrmEnquiry)中编写收到事件后的处理方法(暨更新主页面),代码及层次结构如下:
public partial class FrmEnquiry : DevExpress.XtraEditors.XtraForm
{
… … ……
private void frmEnquiryEdit_EqDocumentSaved(object sender,EqDocumentSavedEventArgs eq)
{
this.enquiryDocuments.Add(eq.EnquiryDocument);
this.gridControl2.RefreshDataSource();
}
… … ……
}
5、在编辑页面(FrmEnquiryEdit)保存新增询价记录按钮方法中添加发布事件代码,代码及层次结构如下:
public partial class FrmEnquiryEdit : DevExpress.XtraEditors.XtraForm
{
… …
private void sBtnSaveEQDoc_Click(object sender, EventArgs e)
{
… …
//发布事件通知主界面更新数据
if (EqDocumentSaved != null)
{
EqDocumentSavedEventArgs eq = new EqDocumentSavedEventArgs(enquiryDocument);
EqDocumentSaved(this, eq);
}
… …
}
}
注:如果没有任何客户将委托与该事件挂钩,该字段将为空;否则该字段引用应在调用该事件时调用的委托。因此,调用事件时通常先检查是否为空,然后再调用事件。
6、在主页面(FrmEnquiry)中新增询价记录按钮方法中订阅新增询价记录事件、代码如下:
public partial class FrmEnquiry : DevExpress.XtraEditors.XtraForm
{ … …
private void sBtnNewEnquiry_Click(object sender, EventArgs e)
{
……
FrmEnquiryEdit frmEnquiryEdit = new FrmEnquiryEdit(enquiryDocument,true);
//先移除事件绑定的所有方法(如果有)
frmEnquiryEdit.ClearEqDocChangedEvent();
//添加新绑定,订阅事件
frmEnquiryEdit.EqDocumentSaved += new EqDocumentsChangedEventHandler(frmEnquiryEdit_EqDocumentSaved);
frmEnquiryEdit.Show();
……
}
… …
}
其中frmEnquiryEdit.ClearEqDocChangedEvent();先清除事件绑定的所有的方法的目的是为了防止事件处理方法被多次调用,其实现代码如下
public partial class FrmEnquiryEdit : DevExpress.XtraEditors.XtraForm
{
… …
public void ClearEqDocChangedEvent()
{
if (EqDocumentSaved != null)
{
EqDocumentSaved.GetInvocationList().ToList().ForEach(p => EqDocumentSaved -= p as EqDocumentsChangedEventHandler);
}
}
… …
}
至此,案例需求实现完成(用户在编辑页面(FrmEnquiryEdit)中编辑完询价记录后在点击保存新增询价记录按钮后编辑界面(FrmEnquiryEdit)需要通知主界面更新显示出刚刚新增询价记录)
二、总结
总结一下事件的使用步骤如下(步骤无需完全按照下面的来,各步骤代码可按自己习惯的顺序编写):
- 如果事件需要传递自定义数据则定义事件传递数据类。
- 定义包装收到事件后的处理方法的委托类,该委托要与事件处理方法的返回值类型和参数个数及类型完全一致,(委托声明的返回值类型、参数与其代表的方法要完全一致。)
- 在事件发布类中定义一个事件(既用2中的委托类声明一个类型为委托的公有事件属性,如:public event 委托类 事件属性名)。
- 在事件订阅类中编写收到事件后的处理方法代码(事件处理方法的返回值类型和参数个数及类型要与委托完全一致)。
- 在发布事件的类中自己想要触发事件的地方发布事件
- 在接收的事件类中订阅事件
小见,案例程序接收的事件类在实例化事件发布后就把事件跟处理方法绑定了,事件的处理方法列表中就不再为null,所以触发事件时及可找到调用的方法。在接收的事件类的不同地方绑定事件处理方法可以有很多变化。