处理FlowLayoutPanel内UserControl内部控件的值更改

时间:2012-04-30 22:49:21

标签: vb.net user-controls event-handling controls flowlayoutpanel

我正在制作发票申请表。我在FlowLayoutPanel(pnlEntries)内部的UserControl(InvoiceEntry)中有一个标签(lblCost)。 InvoiceEntry表示发票上的行项目,pnlEntries是发票的“正文”。 pnlEntries可以包含多个InvoiceEntry控件。

我试图将每个InvoiceEntry控件中的所有lblCost值相加以进行小计,并且我希望在成本发生变化时自动更改小计(例如,订购数量的变化)。有没有办法处理pnlEntries中包含的任何InvoiceEntry控件的lblCost.Text属性何时更改?

InvoiceAdd.vb:

' Instantiate objects of the various database interaction classes.
Private mCustomer As New Customers
Private mItem As New Items
Private mInvoices As New Invoices
Private mInvoiceItem As New InvoiceItems

' An array of InvoiceEntries for DB processing
Private Entries() As InvoiceEntry
Private numEntries As Integer = 0

Private Sub InvoiceAdd_Load(sender As System.Object, e As System.EventArgs) _
            Handles MyBase.Load

    Me.CustomersTableAdapter.Fill(Me.Bauer_BusinessDataSet.Customers)

    ' Set the DataSource properties of the invEntry control.
    ' NOTE: For some reason, if this is done inside the
    ' control code, the program attempts to look in the
    ' wrong directory for the database. I'm not entirely
    ' sure why this is. Setting these properties in the form code,
    ' rather than in the control code, is a successful workaround.
    With invEntry.cboItem
        .DataSource = mItem.Items
        .DisplayMember = "ItemName"
        .ValueMember = "Id"
    End With
End Sub

Private Sub UpdateTotal() Handles nudTaxRate.TextChanged, _
                                  pnlEntries.GotFocus

    Dim total As Decimal = 0

    If Entries IsNot Nothing Then

        For Each x In Entries
            total += CDec(x.lblTotal.Text)
        Next
        lblSubtotal.Text = total.ToString("C")
        lblTax.Text = (lblSubtotal.Text * (nudTaxRate.Text / 100)).ToString("C")

        Dim subtotal As Decimal = 0
        Dim tax As Decimal = 0
        If Not lblSubtotal.Text = Nothing And Not lblTax.Text = Nothing Then
            Decimal.TryParse(lblSubtotal.Text.Substring(1), subtotal)
            Decimal.TryParse(lblTax.Text.Substring(1), tax)
        End If

        lblGrandTotal.Text = (subtotal + tax).ToString("C")
    End If
End Sub

Public Sub invEntry_ItemSelected() Handles invEntry.ItemSelected

    ' Increment the number of entries to reflect the addition of a new entry.
    numEntries += 1

    ' ReDim the Entries array to compensate for a new item being added.
    ReDim Preserve Entries(numEntries - 1)

    ' Store the line item that was selected in the Entries array.
    Entries(numEntries - 1) = invEntry

    ' Set the selected line item to a new blank line item and
    ' add it to the pnlEntries' Controls Collection.
    invEntry = New InvoiceEntry
    With invEntry
        .Name = "Textbox" & numEntries - 1
        .Location = New Point(10, (numEntries - 1) * (.Height + 30))
        With .cboItem
            .DataSource = mItem.Items
            .DisplayMember = "ItemName"
            .ValueMember = "Id"
        End With
    End With
    pnlEntries.Controls.Add(invEntry)

    ' Enable the remove button on the previous list item, as
    ' it is no longer an empty entry.
    Entries(numEntries - 1).btnRemove.Enabled = True

End Sub

Public Sub pnlEntries_ControlRemoved() Handles pnlEntries.ControlRemoved
    numEntries -= 1
    ReDim Preserve Entries(numEntries - 1)

    ' As the Entries array does not know which control was removed,
    ' repopulate it with the controls from the panel.
    ' NOTE: This intentionally leaves the blank line item (invEntry)
    '       out of the array, as this array will be used to add
    '       the invoice line items to the database.
    For x As Integer = 0 To Entries.Count - 1
        Entries(x) = pnlEntries.Controls(x)
    Next
End Sub

InvoiceEntry.vb:

' Instantiate an object to interact with the Item table.
Private mItem As New Items

Public Event ItemSelected As EventHandler

Private Sub cboItem_SelectionChangeCommitted(sender As System.Object, _
                    e As System.EventArgs) _
                    Handles cboItem.SelectionChangeCommitted
    RaiseEvent ItemSelected(Me, EventArgs.Empty)
End Sub

Private Sub InvoiceEntry_Load(sender As System.Object, _
                              e As System.EventArgs) _
                              Handles MyBase.Load

    ' Set the various properties of the Item combobox.
    With cboItem
        .SelectedIndex = -1
        .DropDownStyle = ComboBoxStyle.DropDownList
    End With

    ' Set the Remove button to be disabled by default.
    btnRemove.Enabled = False
End Sub

Private Sub cboItem_SelectedIndexChanged(sender As System.Object, _
                    e As System.EventArgs) _
                    Handles cboItem.SelectedIndexChanged

    ' If nothing is selected, clear and disable all relevant controls.
    If cboItem.SelectedIndex = -1 Or cboItem.Text = "" Then
        lblDescription.Text = ""
        lblTotal.Text = ""
        nudQuantity.Enabled = False
        lblPrice.Text = ""
    Else

        ' Else, set the control texts to their respective values.
        lblDescription.Text = _
            cboItem.DataSource.Rows(cboItem.SelectedIndex)("Description")
        lblPrice.Text = cboItem.DataSource.Rows(cboItem.SelectedIndex)("Price")
        lblTotal.Text = (lblPrice.Text * nudQuantity.Value).ToString("C")
        nudQuantity.Enabled = True
    End If
End Sub

Private Sub lblTotal_TextChanged(sender As System.Object, _
                                 e As System.EventArgs) _
                                 Handles lblTotal.TextChanged

    ' This is part of my workaround that I describe in the comments section
    ' of this StackOverflow question.
    Parent.Focus()
End Sub

Private Sub nudQuantity_ValueChanged(sender As System.Object, _
                                     e As System.EventArgs) _
                                     Handles nudQuantity.TextChanged

    ' If the quantity changes, set the total price to reflect this.
    lblTotal.Text = (lblPrice.Text * nudQuantity.Value).ToString("C")
End Sub

Private Sub btnRemove_Click(sender As System.Object, _
                            e As System.EventArgs) _
                            Handles btnRemove.Click

    ' Remove the control from the parent design.
    Me.Parent.Controls.Remove(Me)
End Sub

1 个答案:

答案 0 :(得分:2)

由于您已经在InvoiceEntry中获得了TextChanged事件处理程序,因此您可以轻松调用InvoiceAdd Form中的UpdateTotal函数

InvoiceEntry.vb

Private Sub lblTotal_TextChanged(sender As System.Object, _
                                 e As System.EventArgs) _
                                 Handles lblTotal.TextChanged

    ' This is part of my workaround that I describe in the comments section
    ' of this StackOverflow question.

    'Parent.Focus()
    'Me.Parent could give you the parent control which is pnlEntry not InvocieAdd form
    'you need to use FindForm here
    Dim MyParentForm As InvoiceAdd = CType(Me.FindForm(), InvoiceAdd)
    MyParentForm.UpdateTotal()
End Sub

InvoiceAdd.vb

Public Sub UpdateTotal() Handles nudTaxRate.TextChanged, _
                                  pnlEntries.GotFocus

    'Change the function to Public

    Dim total As Decimal = 0

    If Entries IsNot Nothing Then

        For Each x In Entries
            total += CDec(x.lblTotal.Text)
        Next
        lblSubtotal.Text = total.ToString("C")
        lblTax.Text = (lblSubtotal.Text * (nudTaxRate.Text / 100)).ToString("C")

        Dim subtotal As Decimal = 0
        Dim tax As Decimal = 0
        If Not lblSubtotal.Text = Nothing And Not lblTax.Text = Nothing Then
            Decimal.TryParse(lblSubtotal.Text.Substring(1), subtotal)
            Decimal.TryParse(lblTax.Text.Substring(1), tax)
        End If

        lblGrandTotal.Text = (subtotal + tax).ToString("C")
    End If
End Sub