Calculate multi TextBoxes

DRGAGI 146 Reputation points
2020-12-12T19:51:36.73+00:00

I have few TextBoxes and i need to calculate sum of all of them into another TextBox or Label, any suggestions? Name of the TextBoxes are: TextBox1, TextBox2 and so on. It is a regular TextBoxes without any data on it.47586-snap2.jpg

VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,644 questions
0 comments No comments
{count} votes

Accepted answer
  1. Karen Payne MVP 35,366 Reputation points
    2020-12-12T21:36:29.92+00:00

    Hello @DRGAGI

    A very simple example, using a class named Item and NumericTextBox (custom TextBox for ensuring only numerics are used and is a very basic TextBox). Full source code is in this GitHub repository.

    47510-a1.png

    Class implementing INotifyPropertyChanged.

    Imports System.ComponentModel  
    Imports System.Runtime.CompilerServices  
      
    Public Class Item  
        Implements INotifyPropertyChanged  
        Private _value1 As Integer  
        Private _value2 As Integer  
        Private _value3 As Integer  
        Private _value4 As Integer  
      
        Public Property Value1() As Integer  
            Get  
                Return _value1  
            End Get  
            Set  
                _value1 = Value  
                OnPropertyChanged()  
            End Set  
        End Property  
      
        Public Property Value2() As Integer  
            Get  
                Return _value2  
            End Get  
            Set  
                _value2 = Value  
                OnPropertyChanged()  
            End Set  
        End Property  
      
        Public Property Value3() As Integer  
            Get  
                Return _value3  
            End Get  
            Set  
                _value3 = Value  
                OnPropertyChanged()  
            End Set  
        End Property  
      
        Public Property Value4() As Integer  
            Get  
                Return _value4  
            End Get  
            Set  
                _value4 = Value  
                OnPropertyChanged()  
            End Set  
        End Property  
      
        Public ReadOnly Property Total() As Integer  
            Get  
                Return Value1 + Value2 + Value3 + Value4  
            End Get  
        End Property  
        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged  
        Protected Overridable Sub OnPropertyChanged(<CallerMemberName> Optional memberName As String = Nothing)  
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(memberName))  
        End Sub  
    End Class  
    

    Numeric TextBox

    Option Infer On  
      
    Imports System  
    Imports System.ComponentModel  
    Imports System.Windows.Forms  
      
    ''' <summary>  
    ''' TextBox which only accepts numeric values along with asserting data copied from the Windows Clipboard  
    ''' </summary>  
    Public Class NumericTextBox  
        Inherits TextBox  
      
        Private WM_KEYDOWN As Integer = &H100  
        Private WM_PASTE As Integer = &H302  
        ''' <summary>  
        ''' Handle key presses for non numeric data  
        ''' </summary>  
        ''' <param name="msg">Window message</param>  
        ''' <returns>bool from base</returns>  
        Public Overrides Function PreProcessMessage(ByRef msg As Message) As Boolean  
            If msg.Msg = WM_KEYDOWN Then  
                Dim keys As Keys = CType(msg.WParam.ToInt32(), Keys)  
      
                Dim numbers As Boolean = ((keys >= Keys.D0 AndAlso keys <= Keys.D9) OrElse  
                                          (keys >= Keys.NumPad0 AndAlso keys <= Keys.NumPad9)) AndAlso  
                                         ModifierKeys <> Keys.Shift  
      
                Dim ctrl As Boolean = keys = Keys.Control  
      
                Dim ctrlZ As Boolean = keys = Keys.Z AndAlso ModifierKeys = Keys.Control,  
                    ctrlX As Boolean = keys = Keys.X AndAlso ModifierKeys = Keys.Control, ctrlC As Boolean = keys = Keys.C AndAlso  
                        ModifierKeys = Keys.Control, ctrlV As Boolean = keys = Keys.V AndAlso  
                        ModifierKeys = Keys.Control, del As Boolean = keys = Keys.Delete,  
                    bksp As Boolean = keys = Keys.Back, arrows As Boolean = (keys = Keys.Up) Or (keys = Keys.Down) Or  
                                                                            (keys = Keys.Left) Or (keys = Keys.Right)  
      
                If numbers Or ctrl Or del Or bksp Or arrows Or ctrlC Or ctrlX Or ctrlZ Then  
                    Return False  
      
                ElseIf ctrlV Then  
                    ' handle pasting from clipboard  
                    Dim clipboardData = Clipboard.GetDataObject()  
                    Dim input = DirectCast(clipboardData.GetData(GetType(String)), String)  
                    For Each character In input  
                        If Not Char.IsDigit(character) Then  
                            Return True  
                        End If  
                    Next character  
                    Return False  
                Else  
                    Return True  
                End If  
            Else  
                Return MyBase.PreProcessMessage(msg)  
            End If  
        End Function  
      
        <Browsable(False)>  
        Public ReadOnly Property AsInteger() As Integer  
            Get  
                Dim value As Integer  
                If Integer.TryParse(Text, value) Then  
                    Return value  
                Else  
                    Return 0  
                End If  
            End Get  
        End Property  
        ''' <summary>  
        ''' Monitor for non-numeric pasted from clipboard  
        ''' </summary>  
        ''' <param name="m">Windows message <see cref="Message"/></param>  
        Protected Overrides Sub WndProc(ByRef m As Message)  
            If m.Msg = WM_PASTE Then  
                Dim clipboardData = Clipboard.GetDataObject()  
                Dim input = CStr(clipboardData?.GetData(GetType(String)))  
                For Each character In input  
                    If Not Char.IsDigit(character) Then  
                        m.Result = New IntPtr(0)  
                        Return  
                    End If  
                Next character  
            End If  
      
            MyBase.WndProc(m)  
      
        End Sub  
    End Class  
    

    Form code

    Imports System.ComponentModel  
      
    Public Class Form1  
        Private BindingList As New BindingList(Of Item)  
      
        Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown  
            BindingList = New BindingList(Of Item) From {New Item() With  
                {.Value1 = 12, .Value2 = 3, .Value3 = 100, .Value4 = 6}}  
      
            NumericTextbox1.DataBindings.Add("Text", BindingList, "Value1")  
            NumericTextbox2.DataBindings.Add("Text", BindingList, "Value2")  
            NumericTextbox3.DataBindings.Add("Text", BindingList, "Value3")  
            NumericTextbox4.DataBindings.Add("Text", BindingList, "Value4")  
            NumericTextbox5.DataBindings.Add("Text", BindingList, "Total")  
        End Sub  
    End Class  
    

    Edit: Dynamic version of the above

    Since you have more TextBoxes then originally thought the following uses a language extension (can be done without an extension yet this is cleaner and usable in any project) to get all NumericTextBoxes into a list. The only downside to this is you need to replace you current TextBox controls with the one I use.

    Namespace Classes  
        Public Module ControlExtensions  
            <Runtime.CompilerServices.Extension>  
            Public Iterator Function Descendants(Of T As Class)(control As Control) As IEnumerable(Of T)  
                For Each child As Control In control.Controls  
      
                    Dim currentChild = TryCast(child, T)  
                    If currentChild IsNot Nothing Then  
                        Yield currentChild  
                    End If  
      
                    If child.HasChildren Then  
                        For Each descendant As T In child.Descendants(Of T)()  
                            Yield descendant  
                        Next  
                    End If  
                Next  
      
            End Function  
            <Runtime.CompilerServices.Extension>  
            Public Function NumericTextBoxList(pControl As Control) As List(Of NumericTextBox)  
                Return pControl.Descendants(Of NumericTextBox)().ToList()  
            End Function  
      
            ''' <summary>  
            ''' Get names of controls   
            ''' </summary>  
            ''' <param name="pControls"></param>  
            ''' <returns></returns>  
            <Runtime.CompilerServices.Extension>  
            Public Function ControlNames(pControls As IEnumerable(Of Control)) As String()  
                Return pControls.Select(Function(c) c.Name).ToArray()  
            End Function  
      
        End Module  
    End Namespace  
    

    Here is all you need in the form.

    Public Class Form1  
        Private BindingList As New BindingList(Of Item)  
      
        Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown  
      
            BindingList = New BindingList(Of Item) From {New Item() With  
                {.Value1 = 0, .Value2 = 0, .Value3 = 0, .Value4 = 0}}  
      
            For Each numericTextBox As NumericTextBox In NumericTextBoxList  
                Dim index = Integer.Parse(Regex.Replace(numericTextBox.Name, "[^\d]", ""))  
                numericTextBox.DataBindings.Add("Text", BindingList, $"Value{index}")  
            Next  
      
            TotalLabel.DataBindings.Add("Text", BindingList, "Total")  
        End Sub  
    End Class  
    

    Note that I use a Label for total this time but could also use a regular TextBox.

    Summary

    We are developers strive to write short, efficient and concise which is all well and good yet short is not always efficient and concise. Then there needs to be a willingness to refactor rather than try to fit a square peg in a around hole. Which brings me to the following point, when I post code it's for your benefit, not mine to allow you and others become better coders.

    Source code has been updated to match the edit section above.


4 additional answers

Sort by: Most helpful
  1. Anonymous
    2020-12-12T21:42:10.793+00:00

    Hi

    Try this as a stand alone example and see if it helps.

    ' Blank FORM1 
    Option Strict On
    Option Explicit On
    Public Class Form1
        Dim lab As New Label
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            ' ==========================
            ' this code block is ONLY for
            ' this example - you have your
            ' controls already on the Form
            Dim y As Integer = 20
            For i As Integer = 1 To 6
                Dim tb As New TextBox
                With tb
                    .Location = New Point(20, y)
                    .Width = 100
                    Controls.Add(tb)
                    AddHandler tb.TextChanged, AddressOf TextBox_TextChanged
                    y += tb.Height + 4
                End With
            Next
            With lab
                .Location = New Point(160, 20)
                .AutoSize = True
                .Font = New Font(.Font.FontFamily, 20)
                Controls.Add(lab)
            End With
            ' ==========================
        End Sub
    
        ' you could probably use thse two 
        ' Subs as a possible answer to
        ' your question
        Private Sub TextBox_TextChanged(sender As Object, e As EventArgs)
            Dim total As Double = 0.0
            For Each c As Control In Controls
                If c.GetType = GetType(TextBox) Then
                    total += GetDouble(c.Text)
                End If
            Next
            lab.Text = total.ToString("0.00")
        End Sub
        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
    End Class
    

  2. DRGAGI 146 Reputation points
    2020-12-12T21:46:01.447+00:00
    Private Sub Button25_Click(sender As Object, e As EventArgs) Handles Button25.Click
            TextBox73.Text = Val(TextBox49.Text) + Val(TextBox50.Text) + Val(TextBox51.Text) + Val(TextBox52.Text) + Val(TextBox53.Text) + Val(TextBox54.Text) + Val(TextBox55.Text) + Val(TextBox56.Text) + Val(TextBox57.Text) + Val(TextBox58.Text) + Val(TextBox59.Text) + Val(TextBox60.Text) + Val(TextBox61.Text) + Val(TextBox62.Text) + Val(TextBox63.Text) + Val(TextBox64.Text) + Val(TextBox65.Text) + Val(TextBox66.Text) + Val(TextBox67.Text) + Val(TextBox68.Text) + Val(TextBox69.Text) + Val(TextBox70.Text) + Val(TextBox71.Text) + Val(TextBox72.Text)
        End Sub
    

    Is this correct way? Looks like it works fine


  3. DRGAGI 146 Reputation points
    2020-12-13T19:50:19.683+00:00

    I want to thank you all for your time and help. You helping me a lot to learn and understand programming. I don't have school of programming because i work too hard and have no time to take some courses to learn, everything i learned is via internet, youtube... This is something that inspiring me and relax me after work. I hope one day i become more experienced and understand better programming language. You are great, thank you again.
    I have so many questions to ask, but i will post them as my project grow and come with new situations.

    0 comments No comments

  4. Albert Kallal 5,226 Reputation points
    2020-12-14T09:52:41.91+00:00

    First up when you drop a text box onto the form, the form designer will "cook up" and give the text box control a name. So you have TextBox64 etc. You can work with those names - but they are hard to work with in code.

    So we do have 10 text boxes "1 to 10". But as you can see, the names above are quite messy.

    So, when you drop a text box, let’s give each text box a name, and start with T1, then T2, then T3 etc.

    You can use any name - but "T" is nice and short - saves the keyboard!!

    So, click on the first text box (our number one), and change the text box name to something that ends with “1”.

    So, we use T1, then T2, then T3 all the way up to T10

    When you click on a text box, display the property sheet. And you can thus change the name here:
    47899-tbox1.png

    So, in above, let’s change then second selected Textbox to T2.

    So this for the 10 boxes. (first one T1, then T2 and then so on!).

    And lets rename our total text box.

    Let’s call it MyTotalBox

    Now, our code to add up the 10 boxes becomes this:

           Dim MyTotal As Double = 0  
      
            Dim strTbox As String  
      
            For i = 1 To 6  
                strTbox = "TextBox" & i  
                If Controls(strTbox).Text <> "" Then  
                    MyTotal = MyTotal + Controls(strTbox).Text  
                End If  
            Next  
      
            ' put our total in the text box called MyTotal  
            MyTotalBox.Text = MyTotal  
      
    

    And note the simple check for if the text box is blank.

    Now, of course over time, one would improve this system, and perhaps reject non numbers in each text box. But, for a BASIC solution (pun intended!!!) then the above will give you some really nice simple tips.

    First up, note how we stuffed a value (string) into a simple variable. Then we used that simple string value to “reference” the control on the form.

    In most cases, you can in code just type in the control name, but since we had 10 of them, and since we gave them a “name convention”, then we can now use a for/next loop on those controls.

    As you journey down this road of learning to code?

    Well, there is ALWAYS more things to learn.

    So, is what you have and wrote the right way? Well, it worked! And that gave you a shot of happy juice. And without those small shots happy and seeing your code run? Seeing your code do something?

    Well, that is just pure joy – not much else can beat the feeling of typing in a bit of code, just a small amount and then seeing and feeling the results.

    And without the above fun shots? Then you not take the next step, the next road, and the next leap in learning about coding.

    Now, we can/could do a MUCH better number check. Once you have the above working (try it!!! - its fun, its short, it is sweet!!!).

    Now we can introduce a more robust number check. We can change the above code to this:

          Dim MyTotal As Double = 0  
            Dim MyCheckNumber As Double = 0  
      
            Dim strTbox As String  
      
            For i = 1 To 6  
                strTbox = "TextBox" & i  
                If Double.TryParse(Controls(strTbox).Text, MyCheckNumber) Then  
                    MyTotal = MyTotal + MyCheckNumber  
                End If  
            Next  
      
            ' put our total in the text box called MyTotal  
            MyTotalBox.Text = MyTotal  
    

    So, in above we introduced a more advanced feature. it is called TryParse. And you can use it to check/test if the value in the text box is in fact a actual number that passes the mustard seed test! If the condition fails, then the expression is false, and we skip. If the value is a number, then it "stuffs" the result of the valid conversion into our variable called MyCheckNumber.

    Enjoy! - and don't forget to try fun things, and simple things - I have fond memories of my first coding experiences - years later I never dreamed about what we can now do with computers. I went on to do computing science, wrote interactive oil spill simulations for oil companies, and much much more!

    But, it all starts out as baby steps. And without the fun, without the simple - then it becomes rather hard to climb these steps - the steps of you first starting to write code! - what a joy!

    Regards,
    Albert D. Kallal (Access MVP 2003-2017)
    Edmonton, Alberta Canada