請求書の申請をしています。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