将用户控件动态添加到 FlowLayoutPanel

Adding a User Control dynamically to a FlowLayoutPanel

我创建了一个 UserControl 并将其添加到 FlowLayoutPanel。 UserControl 用于允许用户在表单中输入 material、成本和交付状态。当用户填写它时,我希望另一个 UserControl 出现在它下面的 FlowLayoutPanel

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

目前我在 FlowLayoutPanel 上有了我的第一个 UserControl,它成功地传递了字符串和 CreateNew 属性。

我遇到的问题是:

  1. 如何监控 CreateNew 是否已更改为 True?
  2. 如何向表单添加控件并为控件名称 +1 以供将来引用
  3. 一旦添加了新的控件,我需要监控新的CreateNew状态是否改变以重复循环

谁能给我指明正确的方向,这方面有很多信息,但我似乎无法从其他人那里找到任何有用的信息 problems/questions。

更新 1

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

这是我使用的代码:

用户控制代码

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" 行收到以下错误:

Unable to cast object of type 'System.Windows.Forms.TextBox' to type 'Alveare_VB.Alv_Product_Order_Control'.

当写入文本框时会引发 CreateNew 事件,这是作为我假设的发件人传回的吗?现在不太确定该去哪里。

编辑 3

错误出在我的 UserControl 中,我发回了不正确的对象(在本例中为文本框)。我现在已经将 RaiseEvent 更改为 return 和 UserControl 作为对象。现在一切正常。

你可以把你的处理程序改成这样

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

但是 last 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 作为逻辑容器。只做对您有用的事情,并考虑删除处理程序。