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.
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.