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:动态创建的月历不会触发 Lost Focus 或 GotFocus