VB.NET动态控件部署

Posted

技术标签:

【中文标题】VB.NET动态控件部署【英文标题】:VB.NET dynamic controls deployment 【发布时间】:2022-01-16 19:29:32 【问题描述】:

下面是一个运行良好的 VBA 代码,它在从 db 表中绘制数据时向允许它们的任何对象添加控件。这很好用,因为这里我有一个 .Add 方法,它允许定义控件类型和名称的 2 个字符串变量。在 VB.Net 上找不到类似的东西。我只能为每种控件类型制作单独的程序。此代码不可用,因为我无法在抽象中构建 MSForms.UserForm。它必须有一个带有表单设计器的原型构建,而这在 VS 上不构建 MSForms.UserForms,而仅构建 System.Windows.Forms。 除了使用大量 Selects、Ifs 和类似方法制作我自己的程序之外,还有什么解决方案吗?这仍然在 VB.6 中有效 - 在 WEB 和这个平台上有历史解决方案。

Function formFill(obj As Object, strSQL As String) As String
Dim rs As ADODB.Recordset, cntr As MSForms.Control, c As String

c = ""
On Error GoTo formFill_err
Set rs = ui_cnt.Execute(strSQL)

Do While Not rs.EOF

    Set cntr = obj.Controls.Add("Forms." + rs("obj_type") + ".1", rs("obj_name"), True)
    cntr.Height = rs("Height")

    If Left(cntr.Name, 3) = "lbl" And cntr.Height > 32 Then cntr.WordWrap = True
    cntr.Left = rs("Left")
    cntr.Top = rs("Top")
    cntr.Width = rs("Width")
    cntr.Caption = str_convert_null(rs("caption"))
    cntr.ControlTipText = str_convert_null(rs("tip"))
    cntr.Font.Size = 8
    cntr.Visible = True
    If Left(cntr.Name, 3) = "txt" Then
        cntr.AutoSize = False
    Else
        cntr.AutoSize = True
    End If

    c = c + rs("obj_type") + ";" + rs("obj_name") + ";"
    rs.MoveNext
Loop

Set rs = Nothing
formFill = c
Exit Function
formFill_err:
If Err.Number = 438 Then Resume Next
End Function

【问题讨论】:

【参考方案1】:

这是一个如何在Windows Form 中创建控件的示例。

首先,为您的控件设置声明一个容器。这是一个替换您的 ADODB.Recordset 对象的类。

Public Class MyControl
    Public Property obj_type As String
    Public Property obj_name As String
    Public Property Top As Integer
    Public Property Left As Integer
    Public Property Height As Integer
    Public Property Width As Integer
    Public Property caption As String
    Public Property tip As String
End Class

这是一个返回我之前定义的类的数组的函数。我对值进行了硬编码(2 个标签和 1 个文本框),但您也可以从其他来源(如数据库中的表)获取值。您可以使用 .Net 的任何数据库技术替换此函数的内容,例如。 ADO.Net 或实体框架 (EF)。

Private Function GetMyControls() As MyControl()

    Return 
        New MyControl With 
            .obj_type = "System.Windows.Forms.Label",
            .obj_name = "lblLabel1",
            .Top = 20,
            .Left = 20,
            .Height = 30,
            .Width = 100,
            .caption = "Label 1 caption",
            .tip = "Label 1 tooltip"
        ,
        New MyControl With 
            .obj_type = "System.Windows.Forms.Label",
            .obj_name = "lblLabel2",
            .Top = 60,
            .Left = 20,
            .Height = 100,
            .Width = 100,
            .caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
            .tip = "Label 2 tooltip"
        ,
        New MyControl With 
            .obj_type = "System.Windows.Forms.TextBox",
            .obj_name = "txtTextbox1",
            .Top = 200,
            .Left = 20,
            .Height = 500,
            .Width = 500,
            .caption = "abcdef",
            .tip = "Textbox 1 tooltip"
        
    

End Function

然后从设置中创建每个控件,然后将其添加到表单的控件集合中。

Private Sub BuildMyControls()

    'get controls setup
    Dim myControls = GetMyControls()

    For Each myControl In myControls

        'get control type
        Dim myControlType = GetType(Control).Assembly.GetType(myControl.obj_type)
        'create control
        Dim cntr As Control = Activator.CreateInstance(myControlType, True)
        'setting properties
        With cntr
            .Name = myControl.obj_name
            .Top = myControl.Top
            .Left = myControl.Left
            .Height = myControl.Height
            .Width = myControl.Width
            .Text = myControl.caption
            .Font = New Font(.Font.Name, 8.0F, FontStyle.Regular)
        End With

        'add an event handler (optional), uncomment the if statement if you want to do it for labels only
        'If myControl.obj_type = "System.Windows.Forms.Label" Then
        AddHandler cntr.Click, AddressOf MyControl_Click
        'End If

        'add new control into form's control collection
        Me.Controls.Add(cntr)
    Next

End Sub

将控件创建方法放在表单的加载事件中。

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    BuildMyControls()
End Sub

Last 是可选的,我为控件单击事件添加了一个事件处理程序。该方法在上面的控件创建方法中被调用。

Private Sub MyControl_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
    Dim cntr = DirectCast(sender, Control)
    'old version (formatted string)
    'Dim message = String.Format("You clicked a 0 named 1", cntr.GetType, cntr.Name)
    'new version (interpolated string)
    Dim message = $"You clicked a cntr.GetType named cntr.Name"
    MessageBox.Show(message)
End Sub

完整代码:

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        BuildMyControls()
    End Sub

    Private Sub MyControl_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Dim cntr = DirectCast(sender, Control)
        'old version (formatted string)
        'Dim message = String.Format("You clicked a 0 named 1", cntr.GetType, cntr.Name)
        'new version (interpolated string)
        Dim message = $"You clicked a cntr.GetType named cntr.Name"
        MessageBox.Show(message)
    End Sub

    Private Sub BuildMyControls()

        'get controls setup
        Dim myControls = GetMyControls()

        For Each myControl In myControls

            'get control type
            Dim myControlType = GetType(Control).Assembly.GetType(myControl.obj_type)
            'create control
            Dim cntr As Control = Activator.CreateInstance(myControlType, True)
            'setting properties
            With cntr
                .Name = myControl.obj_name
                .Top = myControl.Top
                .Left = myControl.Left
                .Height = myControl.Height
                .Width = myControl.Width
                .Text = myControl.caption
                .Font = New Font(.Font.Name, 8.0F, FontStyle.Regular)
            End With

            'add an event handler (optional), uncomment the if statement if you want to do it for labels only
            'If myControl.obj_type = "System.Windows.Forms.Label" Then
            AddHandler cntr.Click, AddressOf MyControl_Click
            'End If

            'add new control into form's control collection
            Me.Controls.Add(cntr)
        Next

    End Sub

    Private Function GetMyControls() As MyControl()

        Return 
            New MyControl With 
                .obj_type = "System.Windows.Forms.Label",
                .obj_name = "lblLabel1",
                .Top = 20,
                .Left = 20,
                .Height = 30,
                .Width = 100,
                .caption = "Label 1 caption",
                .tip = "Label 1 tooltip"
            ,
            New MyControl With 
                .obj_type = "System.Windows.Forms.Label",
                .obj_name = "lblLabel2",
                .Top = 60,
                .Left = 20,
                .Height = 100,
                .Width = 100,
                .caption = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
                .tip = "Label 2 tooltip"
            ,
            New MyControl With 
                .obj_type = "System.Windows.Forms.TextBox",
                .obj_name = "txtTextbox1",
                .Top = 200,
                .Left = 20,
                .Height = 500,
                .Width = 500,
                .caption = "abcdef",
                .tip = "Textbox 1 tooltip"
            
        

    End Function

End Class

Public Class MyControl
    Public Property obj_type As String
    Public Property obj_name As String
    Public Property Top As Integer
    Public Property Left As Integer
    Public Property Height As Integer
    Public Property Width As Integer
    Public Property caption As String
    Public Property tip As String
End Class

我不为自动换行、自动调整大小和工具提示编写代码。

【讨论】:

以上是关于VB.NET动态控件部署的主要内容,如果未能解决你的问题,请参考以下文章

部署 VB.NET 应用程序的最佳方式是啥?

VB.NET ReportViewer 动态绑RDLC

VB.Net:动态创建的月历不会触发 Lost Focus 或 GotFocus

每个新的 ClickOnce 部署版本都会丢失 VB.NET “My.Settings”

VB.NET怎么安装

带有MS访问数据库作为后端的VB.NET如何通过将数据库文件放入AppData文件夹进行部署?