动态生成工具栏类 BqGetToolStrip,师出菜单生成基类 BqGetMenuStrip,其基本功能相同,只是操控对象是前文介绍的BqUToolButton。熟悉前三篇文章的朋友们知道,我这个BqGetToolStrip类,是专门根据数据库中模块权限数据库表,自动生成工具栏按钮的,并且与系统的功能模块相对应,可以直接打开调用窗体。
原代码如下:
vbnet
#Region "全新打造的 工具栏生成 基类 BqGetToolStrip 作者:cdbqss 20260526"
''' <summary>
''' 根据数据库中的模块权限数据表动态生成工具栏(ToolStrip)。
''' 支持图标、权限,并支持通过反射动态绑定 Click、MouseEnter、MouseMove 事件。
''' </summary>
''' <remarks>需要先设置 BqSetTableMode(数据表)、BqSetTargetForm(目标窗体)、BqsEvClick/BqsEvMouseEnter/BqsEvMouseMove(事件方法名),然后通过 BqGetStrip 属性获取生成的工具栏。</remarks>
<Browsable(True), Category("Bqss"), Description("cdbqss属性提示:动态工具栏生成器,生成 ToolStrip")>
Public Class BqGetToolStrip
#Region "私有变量"
Private oToolStip As System.Windows.Forms.ToolStrip
Private ltbMode As DataTable ' 数据表,这个是从数据库获得的数据表
Private lFormTarget As Object ' 目标窗体实例,用于反射调用
Private eEvClick As EventHandler ' 三个事件,传入时必须在窗体定义 Public 事件名,注意大小写和事件参数保持一致
Private eEvMouseEnter As EventHandler
Private eEvMouseMove As MouseEventHandler
#End Region
#Region "公用只写属性"
''' <summary>
''' 设置工具栏数据表(模块权限表)。内部会复制一份数据表,避免原表被修改。
''' </summary>
''' <param name="Value">包含模块信息的 DataTable,必须包含字段:BHmode, BHparent, MCmode, Icon, MarKsy, blnAdd, blnEdi, blnDel, blnPrn, blnBow, blnOut 等。</param>
<Browsable(True), Category("Bqss"), Description("cdbqss属性提示:设置工具栏的数据来源(模块权限表)")>
Public WriteOnly Property BqSetTableMode() As DataTable
Set(ByVal Value As DataTable)
ltbMode = New DataTable
ltbMode = Value.Copy
End Set
End Property
''' <summary>
''' 设置目标窗体实例(用于反射调用事件处理方法)。
''' 务必要先设置窗体实例,后续在设置事件名称时,才能正常进行反射调用
''' </summary>
<Browsable(True), Category("Bqss"), Description("cdbqss属性提示:目标窗体实例,用于动态事件绑定")>
Public WriteOnly Property BqSetTargetForm As Object
Set(value As Object)
lFormTarget = value
End Set
End Property
''' <summary>
''' 设置工具栏按钮 Click 事件对应的方法名称(方法签名必须为 Sub(sender As Object, e As EventArgs))。
''' </summary>
<Browsable(True), Category("Bqss"), Description("cdbqss属性提示:Click 事件绑定的方法名(须符合 EventHandler 签名)")>
Public WriteOnly Property BqsEvClick() As String
Set(value As String)
eEvClick = mSetHandle(lFormTarget, value, GetType(EventHandler))
'Debug.WriteLine(eEvClick)
End Set
End Property
''' <summary>
''' 设置工具栏按钮 MouseMove 事件对应的方法名称(方法签名必须为 Sub(sender As Object, e As MouseEventArgs))。
''' </summary>
<Browsable(True), Category("Bqss"), Description("cdbqss属性提示:MouseMove 事件绑定的方法名(须符合 MouseEventHandler 签名)")>
Public WriteOnly Property BqsEvMouseMove() As String
Set(value As String)
eEvMouseMove = mSetHandle(lFormTarget, value, GetType(MouseEventHandler))
'Debug.WriteLine(eEvMouseMove)
End Set
End Property
''' <summary>
''' 设置工具栏按钮 MouseEnter 事件对应的方法名称(方法签名必须为 Sub(sender As Object, e As EventArgs))。
''' </summary>
<Browsable(True), Category("Bqss"), Description("cdbqss属性提示:MouseEnter 事件绑定的方法名(须符合 EventHandler 签名)")>
Public WriteOnly Property BqsEvMouseEnter() As String
Set(value As String)
eEvMouseEnter = mSetHandle(lFormTarget, value, GetType(EventHandler))
'Debug.WriteLine(eEvMouseEnter)
End Set
End Property
#End Region
#Region "公用只读属性"
''' <summary>
''' 获取返回生成的工具栏(ToolStrip)。如果生成失败或没有按钮项,则返回 Nothing。
''' </summary>
<Browsable(True), Category("Bqss"), Description("cdbqss属性提示:获取生成的 ToolStrip 对象")>
Public ReadOnly Property BqGetStrip As System.Windows.Forms.ToolStrip
Get
Call mReadTable()
If IsNothing(oToolStip) = False AndAlso oToolStip.Items.Count > 0 Then
Return oToolStip
Else
Return Nothing
End If
End Get
End Property
''' <summary>
''' 创建并返回一个工具栏数据表,包含所有必要字段,布尔字段默认值为 True。
''' </summary>
Public ReadOnly Property BqCreateToolTab() As DataTable
Get
Dim ltb As New DataTable
' 添加 Boolean 字段,默认值均为 True
Dim colMarKsy As New DataColumn("MarKsy", GetType(Boolean)) With {.DefaultValue = True}
Dim colAdd As New DataColumn("blnAdd", GetType(Boolean)) With {.DefaultValue = True}
Dim colEdi As New DataColumn("blnEdi", GetType(Boolean)) With {.DefaultValue = True}
Dim colDel As New DataColumn("blnDel", GetType(Boolean)) With {.DefaultValue = True}
Dim colPrn As New DataColumn("blnPrn", GetType(Boolean)) With {.DefaultValue = True}
Dim colBow As New DataColumn("blnBow", GetType(Boolean)) With {.DefaultValue = True}
Dim colOut As New DataColumn("blnOut", GetType(Boolean)) With {.DefaultValue = True}
' ID 自动递增
Dim colID As New DataColumn("ID", GetType(Integer)) With {
.AutoIncrement = True, .AutoIncrementSeed = 1, .AutoIncrementStep = 1}
' 其他字段
Dim colXHmode As New DataColumn("XHmode", GetType(Integer))
Dim colBHmode As New DataColumn("BHmode", GetType(String))
Dim colBHparent As New DataColumn("BHparent", GetType(String))
Dim colFrmName As New DataColumn("FrmName", GetType(String))
Dim colMCmode As New DataColumn("MCmode", GetType(String))
Dim colMeM As New DataColumn("MeM", GetType(String))
Dim colModeAlt As New DataColumn("ModeAlt", GetType(String))
Dim colModeKey As New DataColumn("ModeKey", GetType(String))
Dim colIcon As New DataColumn("Icon", GetType(String))
' 添加所有列到表
ltb.Columns.AddRange({colID, colXHmode, colBHmode, colBHparent, colFrmName, colMCmode,
colMeM, colModeAlt, colModeKey, colIcon,
colMarKsy, colAdd, colEdi, colDel, colPrn, colBow, colOut})
' 设定主键:ID 和 BHmode
ltb.PrimaryKey = {colBHmode, colID}
Return ltb
End Get
End Property
#End Region
#Region "私有方法"
Private Sub mReadTable() '注意,这里与建立菜单栏是不一样的。菜单有上下级,而工具栏不需要
Try
oToolStip = New System.Windows.Forms.ToolStrip
Dim tb, ltb2 As New DataTable
tb = ltbMode.Copy ' 本可以直接用 ltbMode,但为了与原有代码一致,故意加这一行
Dim ltv As DataView = tb.DefaultView
ltv.RowFilter = "计数 > 0"
ltv.Sort = "计数 DESC"
ltb2 = tb.Clone() '把前18个记录另存为ltb2
For i As Integer = 0 To Math.Min(17, ltv.Count - 1)
ltb2.ImportRow(ltv(i).Row)
Next
Dim n As Integer = 0
For Each r As DataRow In ltb2.Rows
Dim mi As New BqUToolButton
' 设置基础属性(权限、模块信息等)
Dim lmMc As String = Trim("" & r("MCmode"))
mi.BqPModMc = lmMc ' 原始模块名称
mi.BqPMoRiAdd = r("blnAdd") ' 新增权限
mi.BqPMoRiEdi = r("blnEdi") ' 修改权限
mi.BqPMoRiDel = r("blnDel") ' 删除权限
mi.BqPMoRiPrn = r("blnPrn") ' 打印权限
mi.BqPMoRiBow = r("blnBow") ' 预览权限
mi.BqPMoRiOut = r("blnOut") ' 导出权限
mi.BqPModBh = "" & r("BHmode") ' 模块编号
mi.BqPModFrm = "" & r("FRMNAME") ' 表单名称
mi.BqPModTip = lmMc & " " & r("MeM") ' 备注内容,加上名称,使得每个工具按钮都能显示文本
mi.BqPMiIcon = "" & r("Icon") ' 图标文件路径
mi.Enabled = r("MarKsy") ' 按钮是否可用(Enabled)
oToolStip.Items.Add(mi)
' 动态绑定事件
If eEvClick IsNot Nothing Then
AddHandler mi.Click, eEvClick
End If
If eEvMouseEnter IsNot Nothing Then
AddHandler mi.MouseEnter, eEvMouseEnter
End If
If eEvMouseMove IsNot Nothing Then
AddHandler mi.MouseMove, eEvMouseMove
End If
n = n + 1
' 每隔三个按钮添加一个分隔线(但不在最后一个按钮后添加)
If n Mod 3 = 0 Then
oToolStip.Items.Add(New ToolStripSeparator())
End If
Next
Catch ex As Exception
Dim eexx As String = ""
Debug.WriteLine(ex)
Debug.WriteLine("在 BqGetToolStrip 类中的 mReadTable 中")
End Try
End Sub
#End Region
#Region "私有函数"
''' <summary>
''' 根据目标对象和方法名创建指定类型的委托。支持 EventHandler 和 MouseEventHandler。
''' </summary>
''' <param name="oTarget">目标窗体实例</param>
''' <param name="sMethName">方法名称</param>
''' <param name="oDelegaType">委托类型(EventHandler 或 MouseEventHandler)</param>
''' <returns>创建的委托,失败返回 Nothing</returns>
Private Function mSetHandle(oTarget As Object, sMethName As String, oDelegaType As Type) As [Delegate]
If oTarget Is Nothing OrElse String.IsNullOrEmpty(sMethName) Then Return Nothing
Try
' 根据委托类型确定参数类型
Dim lTypes1 As Type()
If oDelegaType = GetType(EventHandler) Then
lTypes1 = {GetType(Object), GetType(EventArgs)}
ElseIf oDelegaType = GetType(MouseEventHandler) Then
lTypes1 = {GetType(Object), GetType(MouseEventArgs)}
Else
' 其他类型暂不支持
Return Nothing
End If
Dim method = oTarget.GetType().GetMethod(sMethName, BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance, Nothing, lTypes1, Nothing)
If method Is Nothing Then
Debug.WriteLine($"未找到方法: {sMethName} 参数类型 {String.Join(",", lTypes1.Select(Function(t) t.Name))}")
Return Nothing
End If
Return [Delegate].CreateDelegate(oDelegaType, oTarget, method)
Catch ex As Exception
Debug.WriteLine($"创建委托失败: {sMethName} -> {ex.Message}")
Return Nothing
End Try
End Function
#End Region
End Class
#End Region
具体来说,在BqGetToolStrip中,根据当前操作员,操作最频繁的18个模块,生成按钮,呈现在工具栏上,方便日常快捷调用。
使用示例:
vbnet
'======与工具栏相关的补在这里========================
Dim olBqTool As New BqGetToolStrip
With olBqTool '产生新工具栏
.BqSetTableMode = ltb2
.BqSetTargetForm = Me
.BqsEvClick = "BqClickToolBut"
.BqsEvMouseMove = "mEvMouseMove"
.BqsEvMouseEnter = "mEvMouseEnter"
lTools = .BqGetStrip
End With
这里的数据源 ltb2,我前文一样,来自于模块权限表,只是在表中,我添加了使用"计数"这个统计字段。大家可以根据自己的数据库实际,去计算每个操作员经常调用的前18个模块,赋值给ltb2。
由于这些按钮,都全部摆在工具栏中,所以,我没有设计上下级关系,也只就绑定末级模块(模块是有上下级关系的,各级菜单可以呈现,我觉得工具栏按钮就没有必要了。)
运行结果如图。按钮图片是随机选择的,有点丑,不要笑我哈。
