question

GarySimpson-0619 avatar image
0 Votes"
GarySimpson-0619 asked GarySimpson-0619 commented

Sum Updating a sum already in other textboxes Visual Basic .net

Hi Good People,
When my form loads it will load with textboxes filled currency
example:...

Textbox1 = TxtSubTotal =£100.00
Textbox2 = TxtVAT =£ 20.00
Textbox3 = TxtWaitingTime =£ 0.00
Textbox4 = TxtTolls =£ 0.00
Textbox5 = TxtGross =£120.00

Textbox1, Textbox2, Textbox5 are completed automatically, How do I update the Txtbox5 (TxtGross) when I insert figures into Textbox3 (TxtWaitingTime) and or Textbox4 (TxtTolls). At the moment I have tried many different coding's, But cannot get the right answer required
100518-sums-in-vb-1net.png



 Sub SetTB()
         Dim tot As Decimal = 0D
         For Each c As Control In GroupBox1.Controls
             If c.GetType = GetType(TextBox) Then
                 tot += GetDec(c.Text)
             End If
         Next
    
         'TxtGross.Text = tot.ToString("£0.00")
    
         '' Waiting Time
         'TxtGross.Text = (GetDec(TxtGross.Text) + GetDec(TxtWaitingTime.Text).ToString("£0.00"))
    
         '' VAT charged 
         'TxtTolls.Text = (GetDec(TxtTolls.Text) + GetDec(TxtGross.Text)).ToString("£0.00")
    
         '' Gross + WaitingTime + Tolls
         TxtGross.Text = (GetDec(TxtWaitingTime.Text) + GetDec(TxtTolls.Text) + tot).ToString("£0.00")
     End Sub
    
     Private Sub TxtWaitingTime_TextChanged(sender As Object, e As EventArgs) Handles TxtWaitingTime.TextChanged, TxtTolls.TextChanged
         Dim tb As TextBox = DirectCast(sender, TextBox)
    
         If Not tb.Name = "TxtWaitingTime" AndAlso Not tb.Name = "TxtTolls" AndAlso Not tb.Text.StartsWith("£") Then
             tb.Text = "£" & tb.Text
             tb.SelectionLength = 0
             tb.SelectionStart = tb.Text.Length
    
         End If
    
    
         SetTB()

     End Sub

Another sample of my code...

 Private Sub TxtWaitingTime_TextChanged(sender As Object, e As EventArgs) Handles TxtWaitingTime.TextChanged
    
     Dim sum1 As Decimal = GetDec(TxtGross.Text)
     Dim sum2 As Decimal = GetDec(TxtWaitingTime.Text)
     TxtGross.Text = sum2 + sum1
     TxtGross.Text = FormatCurrency(TxtGross.Text)
     SetTB()
 End Sub
    
 Private Sub TxtTolls_TextChanged(sender As Object, e As EventArgs) Handles TxtTolls.TextChanged
     Dim sum1 As Decimal = GetDec(TxtGross.Text)
     Dim sum2 As Decimal = GetDec(TxtTolls.Text)
     TxtGross.Text = sum1 + sum2
     TxtGross.Text = FormatCurrency(TxtGross.Text)
     SetTB()
 End Sub

Can any of you good people Please help me
Kind Regards
Gary


vs-general
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

cooldadtx avatar image
1 Vote"
cooldadtx answered GarySimpson-0619 commented

The "correct" winforms approach is to use the data binding features of winforms. Specifically you'd create a model to store the values you want shown in the UI. You'd then implement the INotifyPropertyChanged interface on the model to notify any interested code when the property values change. Then you'd wrap the model in a BindingSource. Finally you'd bind the BindingSource to each of the UI elements along with the property they are associated with. Winforms will handle updating the UI after that. Note that data binding also allows you to use formatting (such as currency).

In my experience data binding, when it works, is great but you can quickly get beyond what it can handle. Therefore I prefer the poor man's approach. In the poor man's approach you simply respond to the TextChanged event as you are doing in your sample code. Note that this event is raised as the user types and therefore the entered value may not be valid (even with a formatted textbox). You should always ensure that you handle this case.

Private Sub OnPricesChanged(sender As Object, e As EventArgs) Handles TxtWaitingTime.TextChanged, TxtTolls.TextChanged
    ' Assuming these values are always decimals...
    Dim sum As Decimal = Decimal.Parse(TxtSubTotal.Text) + Decimal.Parse(TxtVAT.Text)

    ' Validate user provided values, treat empty as 0
    Dim waitTime As Decimal, toll As Decimal
    If Not TryGetDecimal(TxtWaitingTime.Text, waitTime) OrElse Not TryGetDecimal(TxtTolls.Text, toll) Then
        ' One or more inputs are invalid, what to do???
        Return
    End If

    sum += waitTime + toll
    TxtGross.Text = FormatCurrency(sum)
End Sub

Private Function TryGetDecimal(input As String, ByRef result As Decimal)
    If Decimal.TryParse(input, result) Then
        Return True
    End If

    ' Special case empty string
    If String.IsNullOrEmpty(input) Then
        result = 0
        Return True
    End If

    result = 0
    Return False
End Function


Assuming everything is correct your code seems reasonable except that you're storing formatted strings in the text boxes and not raw decimals so I assume your GetDec cleans up the values first. Personally I would use a model to handle this and let the UI just handle the formatting.

Public Class Cart
    Public Property Subtotal As Decimal = 100
    Public Property VAT As Decimal = 20

    Public Property WaitTime As Decimal
    Public Property Tolls As Decimal

    Public ReadOnly Property Gross As Decimal
        Get
            Return Subtotal + VAT + WaitTime + Tolls
        End Get
    End Property
End Class

Private Sub OnPricesChanged(sender As Object, e As EventArgs) Handles TxtWaitingTime.TextChanged, TxtTolls.TextChanged

    ' Validate user provided values, treat empty as 0
    Dim result As Decimal
    If Not TryGetDecimal(TxtWaitingTime.Text, result) Then
        ' One or more inputs are invalid, what to do???
        Return
    End If
    cart.WaitTime = result

    If Not TryGetDecimal(TxtTolls.Text, result) Then
        ' One or more inputs are invalid, what to do???
        Return
    End If
    cart.Tolls = result

    ' Update UI
    TxtGross.Text = FormatCurrency(cart.Gross)
End Sub
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi Cooldadtxt
Thank you for getting back to me.
you are correct about the clean-up values with decimals currency symbols

  Function GetDec(s As String) As Decimal
         If s.StartsWith("£") Then
             s = s.Substring(1, s.Length - 1)
         End If
         Dim v As Decimal = 0D
         If Decimal.TryParse(s, v) Then Return v
         Return 0D
     End Function

I have never used a Model Do I import the Model into my form, after creating the Model?

I have typed out the code you kindly put in your answer, but get a lot of errors, Maybe I have to import the model somehow.
Please give me a couple of days to get my head around your suggestion and I will mark your answer.

Thanks again Cooldadtxt
Gary


0 Votes 0 ·

You just add the model class to your project. It is just an example. I put it below the test Form class that I had but generally each class goes in its own file. The subroutine code replaces your existing _TextChanged subs. I used a single method as both textbox handlers do the same thing.

0 Votes 0 ·

Hi cooldadtx

I have had to add another Textbox called ( TxtWaitVAT ) This textbox is for adding VAT (value added tax) I was not told about this Until now.
I have tried altering the code you kindly sent me. But I am getting a wrong answer now. Could you please check the code I've re-written to see where I have gone wrong.

what is happens is when the form Loads TxtSubTotal, TxtVAT, TxtGross have numeric / currency values. When I add to TxtTolls everything is ok with your code.


And when adding numeric values into TxtWaitingTime, I created a sum that Puts the Value Added Tax (VAT) of TxtWaitingTime into the new Textbox called ( TxtWaitVAT ) But the Total is now the wrong answer.

I will have to send the code in a different reply as I do not have have enough characters left

Kind regards
Gary

0 Votes 0 ·
GarySimpson-0619 avatar image
0 Votes"
GarySimpson-0619 answered cooldadtx commented
  ' Assuming these values are always decimals...
         Dim sum As Decimal = Decimal.Parse(GetDec(TxtSubTotal.Text) + Decimal.Parse(GetDec(TxtVAT.Text) + Decimal.Parse(GetDec(TxtWaitVAT.Text))))
         ' Validate user provided values, treat empty as 0
         Dim waitTime As Decimal
         Dim toll As Decimal
         Dim waitVAT As Decimal
    
         'when number change add vat to TxtWaitVAT textbox = sum of TxtWaitingTime * VATRateTextBox
         Dim sum1 As Decimal = Decimal.Parse(GetDec(TxtWaitingTime.Text) / 100 * GetDouble(VATRateTextBox.Text))
    
         TxtWaitVAT.Text = sum1
    
         If Not TryGetDecimal(TxtWaitingTime.Text, waitTime) Then
    
         ElseIf Not TryGetDecimal(TxtTolls.Text, toll) Then
    
         ElseIf Not TryGetDecimal(TxtWaitVAT.Text, waitVAT) Then
             ' One or more inputs are invalid, what to do???
             Return
         End If
    
         'The sums get put into Textbox (TxtGross) 
         sum += waitTime + waitVAT + toll
    
    
         TxtGross.Text = FormatCurrency(sum)
    
    
     End Sub
    
     Private Function TryGetDecimal(input As String, ByRef result As Decimal)
         If Decimal.TryParse(input, result) Then
             Return True
         End If
         ' Special case empty string
         If String.IsNullOrEmpty(input) Then
             result = 0.00
             Return True
         End If
         result = 0
         Return False
     End Function
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I think you're combining my recommended approach to getting the decimal values with yours and then trying to manipulate from there and it is causing issues so let's try again.

Private Function TryGetDecimal(input As String, ByRef result As Decimal)
         ' Convert currency string to decimal
         If Decimal.TryParse(input, System.Globalization.NumberStyles.Currency, null, result) Then
             Return True
         End If
         ' Special case empty string
         If String.IsNullOrEmpty(input) Then
             result = 0.00
             Return True
         End If
         result = 0
         Return False
     End Function
0 Votes 0 ·
cooldadtx avatar image
1 Vote"
cooldadtx answered GarySimpson-0619 commented

Moving to answer to get around comment limit.

Note that in your last code block you initialize sum to subtotal + waitTime + waitVat. But within this code you're calculating waitVat so your sum is going to be off probably. You should add waitVat to the sum after you've calculated the value.

Dim subtotal, vat, waitVat, waitingTime, vatRate, toll As Decimal
Dim sum as Decimal

' Sum static stuff (subtotal, vat, toll, waitTime)
If TryGetDecimal(TxtSubTotal.Text, subtotal) AndAlso TryGetDecimal(TxtVAT.Text, vat) AndAlso TryGetDecimal(TxtTolls.Text, toll)
   AndAlso (TxtWaitingTime.Text, waitTime) Then
   sum = subtotal + vat + toll + waitTime
End If

' Calculate new waitVat and update UI
If TryGetDecimal(VATRateTextBox.Text, vatRate) Then
   waitVat = waitTime / 100 * vatRate

   sum += waitVat
   TxtWaitVat.Text = FormatCurrency(waitVat)
End If

` Update UI
TxtGross.Text = FormatCurrency(sum)

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi cooldadtx
Thanks again for your help,
With the last code you kindly supplied, it did not work, The textbox (TxtGross) stayed blank on form load and during input of (TxtTolls) and (TxtWaitingTime)

I will post the whole code I have now. It seems to work, But I do not know if it is the right way to code this sum. I tried altering your code but I was getting other problems.

Thank you very much cooldadtx for your time and trouble you took to help me.

Kind Regards
Gary

0 Votes 0 ·
GarySimpson-0619 avatar image
0 Votes"
GarySimpson-0619 answered GarySimpson-0619 commented

For cooldadtx

Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
TxtVATRate.Text = "20"

     TxtSubTotal.Text = "£100.00"
     TxtVAT.Text = "£20.00"
     TxtTolls.Text = "0.00"
     TxtWaitingTime.Text = "0.00"
     TxtWaitVAT.Text = "0.00"
     TxtGross.Text = "£120.00"

 End Sub

 Private Sub TxtTolls_Leave(sender As Object, e As EventArgs) Handles TxtTolls.Leave
     If TxtTolls.Text = Nothing Then
         TxtTolls.Text = "0.00"
     Else
         TxtTolls.Text = FormatCurrency(TxtTolls.Text)
     End If

 End Sub

 Private Sub TxtWaitVAT_TextChange(sender As Object, e As EventArgs) Handles TxtWaitVAT.TextChanged
     TxtWaitVAT.Text = FormatCurrency(TxtWaitVAT.Text)
 End Sub

 Private Sub TxtWaitingTime_Leave(sender As Object, e As EventArgs) Handles TxtWaitingTime.Leave


     If TxtWaitingTime.Text = Nothing Then
         TxtWaitingTime.Text = "0.00"
     Else
         Dim TextRate As Double = GetDouble(TxtVATRate.Text)
         Dim WaitTime As Decimal = GetDec(TxtWaitingTime.Text)
         TxtWaitVAT.Text = WaitTime / 100 * TextRate
         TxtWaitingTime.Text = FormatCurrency(TxtWaitingTime.Text)
     End If


 End Sub

 Private Sub OnPricesChanged(sender As Object, e As EventArgs) Handles TxtWaitingTime.TextChanged, TxtTolls.TextChanged
     ' Assuming these values are always decimals...
     Dim sum As Decimal = Decimal.Parse(GetDec(TxtSubTotal.Text) + Decimal.Parse(GetDec(TxtVAT.Text) + Decimal.Parse(GetDec(TxtWaitingTime.Text) +
                          Decimal.Parse(GetDec(TxtWaitVAT.Text) + GetDec(TxtTolls.Text)))))

     Dim waitTime As Decimal
     Dim waitVAT As Decimal
     Dim toll As Decimal


     If Not TryGetDecimal(TxtWaitingTime.Text, waitTime) Then

     ElseIf Not TryGetDecimal(TxtWaitVAT.Text, waitVAT) Then

     ElseIf Not TryGetDecimal(TxtTolls.Text, toll) Then

         ' One or more inputs are invalid, what to do???
         Return
     End If

     'The sums get put into Textbox (TxtGross) 
     sum += waitTime + waitVAT + toll


     TxtGross.Text = FormatCurrency(sum)

 End Sub

 Private Function TryGetDecimal(input As String, ByRef result As Decimal)
     If Decimal.TryParse(input, result) Then
         Return True
     End If
     ' Special case empty string
     If String.IsNullOrEmpty(input) Then
         result = 0
         Return True
     End If
     result = 0
     Return False
 End Function

 Function GetDec(s As String) As Decimal
     If s.StartsWith("£") Then
         s = s.Substring(1, s.Length - 1)
     End If
     Dim v As Decimal = 0D
     If Decimal.TryParse(s, v) Then Return v
     Return 0D
 End Function

 Function GetDouble(s As String) As Double
     Dim v As Double = 0.0
     If Double.TryParse(s, v) Then Return v
     Return 0.0
 End Function

 Private Sub CmdExit_Click(sender As Object, e As EventArgs) Handles CmdExit.Click
     Application.Exit()
 End Sub

End Class

· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Don't mix Leave with TextChanged. Use TextChanged only. You don't need to check if Text is Nothing because it never will be. The code I gave should work fine. If you aren't seeing values update when you change textboxes then you're missing the event handler for the TextChanged event on those columns.

In the example code you posted you are only calling OnPriceChanged when the wait time or tolls changes. Your TextChanged calls are just updating the formatting in the text boxes so they aren't triggering the changes. In theory you should be able to paste my code into your app, hook up the TextChanged event handlers to call the OnPricesChanged and it should work. If it doesn't then please identify what is not working so I can look at what is wrong.

0 Votes 0 ·

Hi Cooldadtx

Thank you very much for your time and trouble to help me out on this problem I had.
I really do appreciate your input.

Thanks again cooldadtx you are brilliant. and hope you might help me in the future if needed.

Best Regards
Gary

0 Votes 0 ·