将用户控件动态添加到FlowLayoutPanel

时间:2016-11-11 12:26:47

标签: vb.net user-controls

我创建了一个UserControl并将其添加到FlowLayoutPanel。 UserControl用于允许用户输入表单的材料,成本和交付状态。当用户填写完毕后,我希望在FlowLayoutPanel

下面显示另一个UserControl

UserControl只根据输入两个TextBox控件的文本和两个Checkbox控件的状态生成一个字符串。它还有一个属性,指示用户何时填写了足够的信息。我想使用此属性来指示生成新的UserControl。

目前我在FlowLayoutPanel上有第一个UserControl,它成功传递了String和CreateNew属性。

我遇到的问题是:

  1. 如何监控以查看CreateNew是否已更改为True?
  2. 如何向表单添加控件,为控件名称添加+1以供将来引用
  3. 添加新控件后,我需要监控以查看新CreateNew状态是否更改以重复循环
  4. 任何人都可以指出我在这方面的正确方向,那里有很多关于此的信息,但我似乎无法从其他问题/问题中找到任何有用的东西。

    更新1

    感谢用户Zaggler的评论,我现在设法让控件在FlowLayoutPanel上创建自己的新实例。但是现在我遇到了一个新问题,它只创建了一个新的用户控件,然后停止了。

    以下是我使用的代码:

    UserControl代码

    Public Class Alv_Product_Order_Control
        Public OutString As String
        Public Event CreateNew()
        Dim CreateNewRaised As Boolean
    
        Private Sub OutputString(sender As Object, e As EventArgs) Handles tbMaterial.TextChanged, tbCost.TextChanged,
            cbDelivered.CheckedChanged, cbOrderPlaced.CheckedChanged
    
            OutString = "¦¦" & tbMaterial.Text & "¦" & tbCost.Text & "¦"
    
            If cbOrderPlaced.Checked = True Then
                OutString = OutString & "Yes¦"
            Else
                OutString = OutString & "No¦"
            End If
    
            If cbDelivered.Checked = True Then
                OutString = OutString & "Yes¦"
            Else
                OutString = OutString & "No¦"
            End If
    
            If tbCost.Text = "" Or tbMaterial.Text = "" Then
            Else
                If CreateNewRaised = False Then
                    RaiseEvent CreateNew() 'Raise the event that's used to signal adding a new control to the layout
                    CreateNewRaised = True 'Create A Latched Boolean that cannot change again in the future
                End If
            End If
        End Sub
    
        Public ReadOnly Property Alv_Product_Order_Control As String
            Get
                Return OutString 'Pass string back to main form
            End Get
        End Property
    

    主要表格代码

    Private Sub CreateSecondPOC() Handles POC1.CreateNew
        FlowLayoutPanel1.Controls.Add(New Alveare_VB.Alv_Product_Order_Control)
    End Sub
    

    我在这里猜测问题是CreateSecondPOC只处理第一个POC1的事件

    如何创建新的Alveare_VB.Alv_Product_Order_Control,将其命名为POC2,并添加处理程序以处理POC2.CreateNew并添加另一个控件?

    修改2

    我知道我已经找到了答案,但我想看看已经提到过的内存泄漏。我已将以下答案中提供的代码更改为:

    Private Sub CreateSecondPOC(ByVal sender As Object, ByVal e As System.EventArgs) Handles POC1.CreateNew
            Try
                Dim oldPoc = DirectCast(sender, Alveare_VB.Alv_Product_Order_Control)
                RemoveHandler oldPoc.CreateNew, AddressOf CreateSecondPOC
            Catch ex As Exception
                Debug.Print(ex.Message)
            End Try
    
            Dim newPoc As New Alveare_VB.Alv_Product_Order_Control
            AddHandler newPoc.CreateNew, AddressOf CreateSecondPOC
            FlowLayoutPanel1.Controls.Add(newPoc)
        End Sub
    

    我在" RemoveHandler"上收到以下错误行:

      

    无法转换类型为#System; Windows.Forms.TextBox'的对象。输入' Alveare_VB.Alv_Product_Order_Control'。

    当写入文本框时会引发CreateNew事件,这会像我假设的发件人那样被传回?现在还不确定该去哪里。

    编辑3

    错误发生在我的UserControl中,我发送了错误的对象(在本例中是文本框)。我现在更改了RaiseEvent以返回UserControl作为对象。现在一切正常。

1 个答案:

答案 0 :(得分:1)

您可以将处理程序更改为此类

Private Sub CreateSecondPOC() Handles POC1.CreateNew
    Dim newPoc As New Alveare_VB.Alv_Product_Order_Control
    AddHandler newPoc.CreateNew, AddressOf CreateSecondPOC
    FlowLayoutPanel1.Controls.Add(newPoc)
End Sub

我不确定你是否想要继续处理这个事件,即使它已被填充一次,也就是说它可以减少,然后重新填充,然后再次举起事件?也许你想在它填充后锁定它,但这并不清楚。

您还可以将所有POC控件保留在容器中,只有在填充完所有时才创建新控件。

修改

根据下面的评论,您应该在不再需要它时删除事件处理程序,以避免内存泄漏。这是一种方式

Private Sub CreateSecondPOC(sender As Object) Handles POC1.CreateNew
    Dim oldPoc = DirectCast(sender, Alveare_VB.Alv_Product_Order_Control)
    RemoveHandler oldPoc, AddressOf CreateSecondPOC
    Dim newPoc As New Alveare_VB.Alv_Product_Order_Control
    AddHandler newPoc.CreateNew, AddressOf CreateSecondPOC
    FlowLayoutPanel1.Controls.Add(newPoc)
End Sub

最后 POC控件的事件处理程序永远不会被取消订阅。所以你在关闭表格时也可以这样做

For Each poc In Me.FlowLayoutPanel1.Controls.OfType(Of Alveare_VB.Alv_Product_Order_Control)()
    RemoveHandler poc.CreateNew, AddressOf CreateSecondPOC
Next poc

我在上面提到您还可以将所有POC控件保存在容器中,这是跟踪控件的更好方法,而不是将FlowLayoutPanel用作逻辑容器。只做适合自己的事情并考虑删除处理程序。