質問

I am making an invoicing application. I have a label (lblCost) inside of a UserControl (InvoiceEntry) inside of a FlowLayoutPanel (pnlEntries). InvoiceEntry represents a line item on the invoice, and pnlEntries is the "body" of the invoice. pnlEntries can hold several InvoiceEntry controls.

I am attempting to sum all of the lblCost values from each InvoiceEntry control to make a subtotal, and I want that subtotal to change automatically if costs are changed (e.g., a change in quantities being ordered). Is there a way to handle when the lblCost.Text property of any of the InvoiceEntry controls contained within pnlEntries changes?

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
役に立ちましたか?

解決

Since you have already got the TextChanged event handler within InvoiceEntry, you can easily call the UpdateTotal function in InvoiceAdd Form

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
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top