VB2026 动态生成工具栏类 BqGetToolStrip

动态生成工具栏类 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。

由于这些按钮,都全部摆在工具栏中,所以,我没有设计上下级关系,也只就绑定末级模块(模块是有上下级关系的,各级菜单可以呈现,我觉得工具栏按钮就没有必要了。)

运行结果如图。按钮图片是随机选择的,有点丑,不要笑我哈。

相关推荐
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题 第85题】【Mysql篇】第15题:MySQL 的事务中,幻读是怎么解决的?
java·开发语言·数据库·mysql·面试
妄想出头的工业炼药师1 小时前
追踪定位大模型
算法·开源
yoothey1 小时前
MySQL 索引小白面试详解
数据库·mysql
dishugj1 小时前
oracle索引unusable/disable/invisible的区别
oracle
一 乐1 小时前
在线考试|基于Springboot的在线考试管理系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·毕设·在线考试管理系统
玄米乌龙茶1231 小时前
数据库与缓存核心概念
数据库·缓存
小陈的进阶之路1 小时前
MySQL 索引
数据库·mysql
宝桥南山1 小时前
Microsoft Agent Framework(MAF) - 如何将workflow或者A2A client转换成一个AI Agent
microsoft·ai·微软·aigc·.net·.netcore
無限進步D1 小时前
MySQL 子查询
数据库·mysql