基于组合框选择动态添加自定义用户控件到表单,无需条件循环

时间:2015-09-14 13:34:00

标签: vb.net winforms combobox user-controls dynamic-controls

我正在开发一个项目,该项目要求用户为其客户创建未指定数量的捕获字段。在这样做时,我想创建一个通用模板,其中他们键入新字段的名称,并从组合框中选择一个类型。组合框的值('自由文本'布尔','十进制'等)可以存储在任何地方(即我不挑剔)关于他们如何约束)。 selectedIndexChanged事件将处理相应的usercontrol的添加。但是,由于我不知道我将处理多少值类型(现在看起来像7-9),我想避免使用以下类型的代码:

Private Sub cbxType_SelectedIndexChanged(sender As Object, e As EventArgs)
    If cbxType.SelectedItem = "Free Text" Then
        Dim vText As VTText = New VTText() ' This is the usercontrol for text
        Controls.Add(vText)
    ElseIf cbxType.SelectedItem = "Boolean" Then
        Dim vBool As VTBool = New VTBool() ' etc.
    ...

我的第一个想法是在表单加载

时使用某种键值对的列表/字典
Dim kList As List(Of KeyValuePair(Of String, Object)) = New List(Of KeyValuePair(Of String, Object))
kList.Add(New KeyValuePair(Of String, Object)("Text", New vText())
For each kpair As KeyValuePair(Of String, Object) In kList
    cbx.Items.Add(kPair.Key)
Next

在更改事件处理程序中使用类似的东西

Dim myControl = DirectCast(cbxType.SelectedItem, KeyValuePair(Of String, Object)).Value
Controls.Add(myControl)

但是,selectedvalue属性为空,我得到一个无效的强制转换异常。我试过转换为Control和UserControl,但那些当然没有用。 这种做法,除非我的错误实施,听起来不错?有一个更好的方法吗?理想情况下,我想要一条有效地执行此类操作的行:

Controls.Add(cbxType.SelectedValue)

2 个答案:

答案 0 :(得分:1)

您可以创建一个类来保存控件以及显示文本,并将这些对象绑定为组合框的数据源。然后,您就可以实现一个衬垫,以便为您的收藏添加控件。

示例(假设我有一个带有组合框(Combobox1)和一个Button(Button1)的表单:

Public Class Form1

   Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
       If (Not ComboBox1.SelectedItem Is Nothing) Then
          GroupBox1.Controls.Add(Activator.CreateInstance(ComboBox1.SelectedItem.ControlType))
       End If
   End Sub

   Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
       'add some controls to the cbx
       Dim ctrl As New MyControl
       ctrl.DisplayText = "TextBox"
       ctrl.ControlType = GetType(System.Windows.Forms.TextBox)
       Me.ComboBox1.Items.Add(ctrl)
      End Sub
End Class
Public Class MyControl 'The thing that i have also done is add the Display Memeber and Value Member on my Combobox.
    Public DisplayText As String
    Public ControlType As Type
End Class

答案 1 :(得分:1)

这是另一个类似于DotNetHitMan之前建议的选项......

首先,在UserControls中覆盖 ToString(),以设置它们在ComboBox中的显示方式。例如:

Public Class VTText

    ' ... other code in your UserControl ...

    Public Overrides Function ToString() As String
        Return "Free Text"
    End Function

    ' ... other code in your UserControl ...

End Class

Public Class VTBool

    ' ... other code in your UserControl ...

    Public Overrides Function ToString() As String
        Return "Boolean"
    End Function

    ' ... other code in your UserControl ...

End Class

接下来,将ComboBox的 FormattingEnabled 设置为False,并在Form的Load()事件中将UserControl的实例直接添加到ComboBox:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    ComboBox1.FormattingEnabled = False
    ComboBox1.Items.Add(New VTText)
    ComboBox1.Items.Add(New VTBool)
    ' ... etc ... (one entry per type of your UserControls)
End Sub

现在添加一个模块,以便为Control创建扩展方法,允许您根据传入的Control类型创建一个新实例:

Public Module Extensions

    <Runtime.CompilerServices.Extension()>
    Public Function GetNewInstance(ByVal ctl As Control) As Control
        Return Activator.CreateInstance(ctl.GetType)
    End Function

End Module

最后,在Button click处理程序中,将ComboBox.SelectedItem强制转换为Control并调用 GetNewInstance()扩展函数:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    If ComboBox1.SelectedIndex <> -1 Then
        Dim ctl As Control = DirectCast(ComboBox1.SelectedItem, Control).GetNewInstance
        ' ... do other stuff with "ctl" ? ...
        FlowLayoutPanel1.Controls.Add(ctl)        
    End If
End Sub