现在开发的一个 vb.net系统,其中有两个窗体:alert窗体和 case窗体。
在alert窗体中列出了当前可以操作的若干个alert(可以理解为数据记录),用户可以选择将其中一个或几个alert加入一个case(可以理解为若干条记录的集合)中。
加入case的这个操作要调用case窗体来完成,由于同时要输入一些相关信息,所以完成时间未知;由于在case窗体中也可能删除某些alert,所以哪些alert最后能够成功加入case也是未知的。
这些alert加入case以后,在alert窗体中要以彩色显示。
上面这个功能,可以使用委托来实现。下面对此进行介绍。
用拟人化的方式来解释:alert窗体,相当于公司的经理,经理手里有若干条工作任务需要完成,但经理自己不会做,只能让公司员工去做;case窗体,相当于公司员工,要去完成经理交代的任务;经理和员工之间,需要有一个沟通的渠道(比如:电话、电报、电邮、小黑板、对讲机,等等),这个渠道既不属于经理,也不属于员工,而是与经理和员工平等的,这个沟通渠道就是委托机制。经理通过这个渠道安排员工去完成某几项工作任务,员工何时能够完成不知道,能够完成几项也不知道,但是员工做完的时候,会返回给经理已经完成的工作清单,经理根据这份工作清单刷新自己手里的任务列表。
下面是相关的代码:
' 在类定义的外面,定义了一个委托,以便在不同的类之间传递信息,这就是沟通渠道
' 具体来说,经理类( frmSuspiciousAlert )调用了 员工类(_frmSuspiciousAlert_case)
' 经理让员工干活(把几笔交易加入到case中),但是什么时候能干完,经理不知道;员工具体添加了哪几笔交易,经理也不知道
' 因此让员工在干完活之后告诉经理一声,并返回所添加的交易的行号
' 这就是这个委托的功能
Public Delegate Sub CallBackManager_saveCase(ByVal rowIDs As List(Of String), ByVal caseID As Integer) ' 委托1,沟通渠道
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Public Class _frmSuspiciousAlert_case ‘ case窗体,公司员工
Dim myCallBack_saveCase As CallBackManager_saveCase ' 委托2: 作为员工,要有能够通知经理的基本能力(不论具体方式:打电话,发短信,发电邮...)
' 注意: 有这个能力不代表一定会去做,具体做不做,取决于经理有没有交待员工这样做
' 委托3: 这里是个供经理调用的接口,经理通过这个接口交待员工(注册一个委托,表示干这个活是经理委派的)
Public Sub registerDelegate_saveCase(ByVal _callBack As CallBackManager_saveCase)
myCallBack_saveCase = _callBack
End Sub
' 构造函数,参数为一个 dataTable ,一个 caseID 和 一个可以操作的caseID列表 ; add to case
' 此时的操作是将这个dataTable中的若干笔交易添加到这个已有的Case中; 若_caseID为0 则添加到新的case
Sub New(_dataTable As DataTable, _caseID As Integer, _enabledCaseIDs As List(Of Integer))
InitializeComponent()
enabledCaseIDs = _enabledCaseIDs
lbl_caseID.Text = _caseID.ToString ' 添加到case
' 注意,由于查看case时 tb_caseID.Text不为0 ' 所以,当 tb_caseID.Text = 0 时,表示添加交易到新的case
newDataTable = _dataTable
End Sub
' 员工干活: 当点击此按钮时,把界面上显示的这些case信息保存到数据库中
Private Sub btn_save_Click(sender As Object, e As EventArgs) Handles btn_save.Click
' 准备返回给经理(frmSuspiciousAlert)的字符串列表: 添加成功的各个rowID
Dim listRowID_added As List(Of String) = New List(Of String)
conn.BeginTrans() ' 开始事务处理
If saveDatasOK(listRowID_added) Then ' 如果存盘成功(listRowID_added,完成的工作清单)
conn.CommitTrans() ' 提交更改
If IsNothing(myCallBack_saveCase) = False Then ' 如果 事先有个委托(这个委托不是空的,表示干这个活是受经理委派的)
myCallBack_saveCase.Invoke(listRowID_added, CInt(lbl_caseID.Text)) ' 委托4: 告知经理,活干完了,并且交上一份工作清单;
‘ 注意: 如果经理(frmSuspiciousAlert)那里有个公共操作(ddd),这里也可以直接对其操作, 'frmSuspiciousAlert.ddd(listRowID) ’ 看上去效果似乎差不多;但是其有弊端(只有在知道经理是谁的情况下,才能这样做; 而且这样直接操作其他页面, 也是不安全的,耦合性也很高),所以如果不知道谁是经理(不知道哪个页面调用了本页面),就只能用委托了 所以,尽量不要使用这种方式
' 由于这里有个委托,所以经理(frmSuspiciousAlert)那里会有个操作(刷新界面),此时活动界面(焦点)会转移到经理那边
Me.Focus() ' 这里重新获取焦点,本界面又成为活动界面
End If
Else ' 如果存盘失败
conn.RollbackTrans() ' 回滚
End If
End Sub
Private Function saveDatasOK(ByRef listRowID_added As List(Of String)) As Boolean
Dim strTableName As String = " AT2_SSIS_SUS_ALERTS "
Dim oReturnNonQuery As QueryReturnReader
Dim commitsuccess As Boolean = True
For Each _row As DataGridViewRow In dgv_alerts.Rows ' 对于 dgv 中的每一行(一行就是一个alert)
Dim strCmd As String = "update " & strTableName & " set " ' 所要更新的表
strCmd &= " CASE_ID = " & CInt(lbl_caseID.Text) '_caseID ' case ID
Dim rowID As String = _row.Cells("rowid").Value().ToString.Trim
listRowID_added.Add(rowID) ' 完成了一项工作,加入清单中
strCmd &= " where rowid = '" & rowID & "'" ' 所要更新的位置
End Function
End Class
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Public Class frmSuspiciousAlert ‘ alert窗体,公司经理
' 当鼠标右键点击进入菜单 Add To New Case 时,将当前选中的这几笔交易加入到某个 可疑Case中
Private Sub clickTSM_addToCase(ByVal sender As Object, ByVal e As System.EventArgs) Handles TSMI_AddToCase.Click
Dim _dt As DataTable = getDataTableFromDgv(dtgAML, True) ' 获取当前dgv的选中的那些行组成的 dataTable(所需要完成的工作清单)
' 首先实例化对象(安排一个员工去干活),将这几笔交易加入到 新的(caseID 为 0) 或者 已有的 case 中
Dim frm As _frmSuspiciousAlert_case = New _frmSuspiciousAlert_case(_dt, caseID, dgvCaseIDs)
' 这里加了个委托,当操作成功时(成功将若干笔交易加入case),返回一个信号,以便改变 dgv的显示状态(行的颜色,行头,等等)
' 委托5: 对员工(_frm2)交待(registerDelegate):你干完活要通知经理(CallBackManager),以便经理这里收尾工作(doThingWhenCallBack)
frm.registerDelegate_saveCase(New CallBackManager_saveCase(AddressOf changeDGV_bySaveCaseResults))
frm.Show() ' 员工干活去了,何时能够干完?不知道
End Sub
‘ 当员工干完时,根据员工返回的清单,经理刷新已经完成的工作清单
Private Sub changeDGV_bySaveCaseResults(ByVal listRowID As List(Of String), ByVal caseID As Integer)
'MessageBox.Show("经理我知道了,这些交易已经成功保存到case " & listRowID.Count)
For Each _rowID As String In listRowID
For Each _row As DataGridViewRow In dtgAML.Rows ' 对于 dgv中一些行 ,如果改变了某个交易的case状态,则改变其底色
If _row.Cells("rowid").Value().ToString.Trim = _rowID Then
_row.DefaultCellStyle.BackColor = color_inCase ' 底色变色
_row.HeaderCell.Value = caseID.ToString ' caseID
_row.ReadOnly = True ' 只可读
End If
Next
Next
End Sub
End Class