# How to calculate average with only one input at a time?

• ### Question

• Hey So I'm currently making a program for employees pay. Its a wpf form using visual basic code.

So i currently have a form that has a textbox to enter employees name and a textbox to enter employees messages sent. Then I have a label for total pay for one employee then a label for total pay for all employees and then the average for all employees.

So my question is how do I calculate the average and total pay for the employees when I can only enter one at a time. Or is that even possiblee? I've ben stuck for a while and honestly dont know where to begin.

I started with making a do while loop and having a variable starting at zero or whatever thats called. But I dont really understand how it works to be honest.

Can anyone help?

```Option Strict On
Class MainWindow
'PieceworkWorker.vb
'        Title: IncInc Payroll(Piecework)
'   Written By: Deanna Slotegraaf
'Adapted from PieceworkWorker by Kyle Chapman, September 2019

'This Is a class representing individual worker objects. Each stores
'their own name And number Of messages And the Class methods allow For
'calculation of the worker's pay and for updating of shared summary
'values. Name And messages are received as strings.
'This Is being used as part of a piecework payroll application.

'This Is currently incomplete; note the four comment blocks
'below that begin With "TO DO"

Public Class pieceworkworker

#Region "variable declarations"

' instance variables
Public employeename As String
Private employeemessages As Integer
Private employeepay As Decimal

Private isvalid As Boolean = True

' shared class variables
Private Shared overallnumberofemployees As Integer
Private Shared overallmessages As Integer
Private Shared overallpayroll As Decimal

#End Region

#Region "constructors"

''' <summary>
''' pieceworkworker constructor: accepts a worker's name and number of
''' messages, sets and calculates values as appropriate.
''' </summary>
''' <param name="namevalue">a worker's name</param>
''' <param name="messagesvalue">a worker's number of messages sent</param>
Friend Sub New(ByVal namevalue As String, messagesvalue As String)

' validate and set the worker's name
Me.name = namevalue
' validate and set the worker's number of messages
Me.messages = messagesvalue
' calculcate the worker's pay and update all summary values
findpay()

End Sub

''' <summary>
''' pieceworkworker constructor: empty constructor used strictly for
''' inheritance and instantiation
''' </summary>
Friend Sub New()

End Sub

#End Region

#Region "class methods"

''' <summary>
''' currently called in the constructor, the findpay() method is
''' used to calculate a worker's pay using threshold values to
''' change how much a worker is paid per message. this also updates
''' all summary values.
''' </summary>
'''
Private Sub findpay()

If (employeemessages >= 1 And employeemessages <= 2499) Then
employeepay = CDec(employeemessages * 0.018)

End If

If (employeemessages >= 2500 And employeemessages <= 4999) Then
employeepay = CDec(employeemessages * 0.024)
End If

If (employeemessages >= 5000 And employeemessages <= 7499) Then
employeepay = CDec(employeemessages * 0.03)
End If

If (employeemessages >= 7500 And employeemessages <= 10000) Then
employeepay = CDec(employeemessages * 0.035)
End If

If (employeemessages > 10000) Then
employeepay = CDec(employeemessages * 0.04)
End If

End Sub

#End Region

#Region "property procedures"

''' <summary>
''' gets and sets a worker's name
''' </summary>
''' <returns>an employee's name</returns>
Friend Property name() As String
Get
Return employeename
End Get
Set(namevalue As String)
If (String.IsNullOrEmpty(employeename)) Then
MessageBox.Show("error! must enter a name")
Else
findpay()

End If

employeename = namevalue

End Set
End Property

''' <summary>
''' gets and sets the number of messages sent by a worker
''' </summary>
''' <returns>an employee's number of messages</returns>
Friend Property messages() As String
Get
Return employeemessages.ToString()
End Get
Set(messagesvalue As String)

If employeemessages > 0 Then
findpay()
Else
MessageBox.Show("error! number must be a positive number")
End If

employeemessages = CInt(messagesvalue) ' this line is dangerous and should probably never appear in your code. can you explain why? post about it on the q&a board and i'll give you a stock.

End Set
End Property

''' <summary>
''' pay(): gets the worker's pay
''' </summary>
''' <returns>a worker's pay</returns>
Friend ReadOnly Property pay() As Decimal
Get
Return employeepay
End Get
End Property
''' <summary>
''' totalpay(): gets the overall total pay among all workers
''' </summary>
''' <returns>the overall total pay among all workers</returns>
Friend Shared ReadOnly Property totalpay() As Decimal
Get
Return overallpayroll
End Get
End Property
''' <summary>
''' gets the overall number of workers
''' </summary>
''' <returns>the overall number of workers</returns>
Friend Shared ReadOnly Property totalworkers() As Integer
Get
Return overallnumberofemployees
End Get
End Property
''' <summary>
''' gets the overall number of messages sent
''' </summary>
''' <returns>the overall number of messages sent</returns>
Friend Shared ReadOnly Property totalmessages() As Integer
Get
Return overallmessages
End Get
End Property
''' <summary>
''' calculates and returns an average pay among all workers
''' </summary>
''' <returns>the average pay among all workers</returns>
Friend Shared ReadOnly Property averagepay() As Decimal
Get
Dim messages As Integer = 0
Do While (messages < 10)
messages = messages + 1
Loop

End Get
End Property

#End Region

End Class

Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
Dim employeemessages As Integer

employeemessages.findpay(lblTotalPay)

End Sub

End Class```

My code ^

Saturday, September 21, 2019 4:06 PM

### All replies

• Hi

Here is one way: this example code is a stand alone and to try, set up Form1 as shown and copy/replace all this code in Form1 code.

The controls are as follows: Panel1 contains TextBoxes 1, 2 1nd 3 for employee1 wages, Panel2 with TextBoxes 10,11 and 12 for employee2 wages.

TextBoxes 4 and 8n(NOT in Panels, for total wages for each employee.

TextBox9 for average earnings for allemployees.

This is NOT the best way to acheive desired result, but is one of many possibilities.

```' Form1 with Panel1 containing
' TextBoxes 1,2,3  and Panel2
' containing TextBoxes 10,11,12
' TextBoxes 4 and 8 for emp total
' TextBox9 for Overall Average
Option Strict On
Option Explicit On
Public Class Form1
Private Sub TextBox_TextChanged(sender As Object, e As EventArgs) Handles TextBox3.TextChanged, TextBox2.TextChanged, TextBox12.TextChanged, TextBox11.TextChanged, TextBox10.TextChanged, TextBox1.TextChanged
Dim tb As TextBox = CType(sender, TextBox)
Dim p As Control = tb.Parent

Select Case p.Name
Case "Panel1"
' tb1-2-3
TextBox4.Text = (GetDecimal(TextBox1.Text) + GetDecimal(TextBox2.Text) + GetDecimal(TextBox3.Text)).ToString("0.00")
Case "Panel2"
' tb10-11-12
TextBox8.Text = (GetDecimal(TextBox10.Text) + GetDecimal(TextBox11.Text) + GetDecimal(TextBox12.Text)).ToString("0.00")
End Select
TextBox9.Text = ((GetDecimal(TextBox4.Text) + GetDecimal(TextBox8.Text)) / 2).ToString("0.00")
End Sub
Function GetDecimal(s As String) As Decimal
Dim v As Decimal = 0
If Decimal.TryParse(s, v) Then Return v
Return -1
End Function
End Class```

Regards Les, Livingston, Scotland

Saturday, September 21, 2019 5:12 PM
• Yeah but see this is my form so I only enter one at a time

Saturday, September 21, 2019 5:33 PM
• Yeah but see this is my form so I only enter one at a time

Hi

OK, but where is the workers pay entered?

Regards Les, Livingston, Scotland

Saturday, September 21, 2019 5:50 PM
• the point of the program is to enter the messages and have the pay calculated based on numbers from this chart i have  it says that in the code
Saturday, September 21, 2019 6:35 PM
• Hello,

I'm going to throw some ideas at you which may take some time to sink in. Focus not if I got what you are looking for done pat but instead a concept of using classes.

I would recommend not performing operations current done in the window unless absolutely necessary. If you are working against many employees place them in a container such as a List of DataTable.

An Employee might look something similar to this (I added department identifier as if there were more than one that would be a static list or obtained from a file or database table). The overloads are custom equality (not to be concerned with presently.

```Public Class Employee
Implements IEquatable(Of Employee)

Public Property EmployeeIdentifier() As Integer
Public Property FirstName() As String
Public Property LastName() As String
Public Property DepartmentIdentifier() As Integer
Public Property Salary() As Decimal
Public Property Messages() As Integer
Public Overloads Function Equals(other As Employee) As Boolean Implements IEquatable(Of Employee).Equals

Return other.FirstName.AreEqual(FirstName) AndAlso
other.LastName.AreEqual(LastName) AndAlso
other.DepartmentIdentifier = DepartmentIdentifier

End Function

Public Overrides Function GetHashCode() As Integer

Return StringComparer.OrdinalIgnoreCase.GetHashCode(FirstName) Xor
StringComparer.OrdinalIgnoreCase.GetHashCode(LastName) Xor
StringComparer.OrdinalIgnoreCase.GetHashCode(DepartmentIdentifier)

End Function

Public Overrides Function ToString() As String
Return \$"{EmployeeIdentifier} {FirstName} {LastName} {DepartmentIdentifier}"
End Function
End Class```

To run through calc (which may not be exact yet you should get the idea and this is but one method) create some mocked data.

```Public Class MockedData
Public Function EmployeeList() As List(Of Employee)
Return New List(Of Employee) From
{
New Employee() With {.EmployeeIdentifier = 1, .FirstName = "Jim", .LastName = "Jones", .Messages = 10000},
New Employee() With {.EmployeeIdentifier = 2, .FirstName = "Mary", .LastName = "Conner", .Messages = 4999},
New Employee() With {.EmployeeIdentifier = 3, .FirstName = "Kate", .LastName = "Miller", .Messages = 7498}
}
End Function
End Class

```

```Dim employeeOperation = New MockedData
Dim employeeList = employeeOperation.EmployeeList()```

Get average salary

`Dim employeeAverage = employeeList.Average(Function(emp) emp.Salary)`

Perform calculation, in this case using extension methods (AreEqual is for equality in the Employee class).

We are interested in CalculatePay which makes uses of Between above.

```Public Module Extensions
''' <summary>
''' Perform case insensitive equal on two strings
''' </summary>
''' <param name="sender"></param>
''' <param name="item"></param>
''' <returns>true if both strings are a match, false if not a match</returns>
<Runtime.CompilerServices.Extension>
Public Function AreEqual(sender As String, item As String) As Boolean
Return String.Equals(sender, item, StringComparison.OrdinalIgnoreCase)
End Function
<Runtime.CompilerServices.Extension>
Public Function Between(Of T)(sender As IComparable(Of T), minimumValue As T, maximumValue As T) As Boolean
Return sender.CompareTo(minimumValue) >= 0 AndAlso sender.CompareTo(maximumValue) <= 0
End Function
<Runtime.CompilerServices.Extension>
Public Sub CalculatePay(sender As List(Of Employee), EmployeeIdentifier As Integer)
Dim employee = sender.FirstOrDefault(Function(emp) emp.EmployeeIdentifier = EmployeeIdentifier)
If employee IsNot Nothing Then
If employee.Messages.Between(1, 2499) Then
employee.Salary = CDec(employee.Messages * 0.018)
ElseIf employee.Messages.Between(2500, 4999) Then
employee.Salary = CDec(employee.Messages * 0.024)
ElseIf employee.Messages.Between(5000, 7499) Then
employee.Salary = CDec(employee.Messages * 0.03)
ElseIf employee.Messages.Between(7500, 10000) Then
employee.Salary = CDec(employee.Messages * 0.035)
ElseIf employee.Messages > 10000 Then
employee.Salary = CDec(employee.Messages * 0.04)
End If
End If
End Sub
End Module```

Calculate

```Dim employeeOperation = New MockedData
Dim employeeList = employeeOperation.EmployeeList()

employeeList.CalculatePay(2)```

Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

NuGet BaseConnectionLibrary for database connections.

StackOverFlow

Sunday, September 22, 2019 1:01 AM
• Yeah but see this is my form so I only enter one at a time

Hi

Been away for a couple of days, had started this so will post it. I see Karen has already taken care of your issue so this post is only an extra way to tackle it.

This is a stand alone example. If you want to try it, add the controls shown in the Designer and copy/replace all the Form1 code with this. This version saves and reloads the Employee database (tothe DeskTop - can be changed)

There are a number of issues with the concept - such as: if the User clicks the Calculate button repeatedly then each click will repeat the add of messages for the employee (I had it clear the Messages textbox but you might want it either way). Another. Negative value for messages can be entered (can be prevented)

Other such issues may need sorting out.

Anyway, here it is:

```' Form1 with TextBoxes 1-5
' (3, 4 and 5) readonly
Option Strict On
Option Explicit On
Public Class Form1
Dim Employees As New Dictionary(Of String, Employee)

' where to load/save Employees data
Dim DataPath As String = IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "EmployeeData.dat")
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
SaveEmployees()
End Sub
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If TextBox1.Text.Length < 1 Then Exit Sub
If Not Employees.Keys.Contains(TextBox1.Text) Then
' add new employee to employees
AddEmployee(New Employee() With {.Name = TextBox1.Text})
End If
Else
End If
FillFields()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
TextBox1.Clear()
TextBox2.Clear()
TextBox3.Clear()
TextBox4.Clear()
TextBox5.Clear()
End Sub
Public Sub SaveEmployees()
Dim fs As IO.FileStream = New IO.FileStream(DataPath, IO.FileMode.OpenOrCreate)
Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
bf.Serialize(fs, Employees)
fs.Close()
End Sub
If FileIO.FileSystem.FileExists(DataPath) Then
Employees.Clear()
Dim fsRead As New IO.FileStream(DataPath, IO.FileMode.Open)
Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
Employees = CType(bf.Deserialize(fsRead), Dictionary(Of String, Employee))
End If
End Sub
Sub FillFields()
Dim tp As Decimal = 0@
If Employees.Keys.Contains(TextBox1.Text) Then
TextBox3.Text = GetPay(TextBox1.Text).ToString("0.00")
Else
TextBox3.Text = 0@.ToString("0.00")
End If

TextBox4.Text = GetTotalPayAllEmployees.ToString("0.00")
TextBox5.Text = GetAveragePayAllEmployees.ToString("0.00")
End Sub

Function GetAveragePayAllEmployees() As Decimal
Dim tp As Decimal = 0@
Try
tp = GetTotalPayAllEmployees() / Employees.Count
Catch ex As DivideByZeroException
End Try
Return tp
End Function

Function GetTotalPayAllEmployees() As Decimal
Dim tot As Decimal = 0@
For Each em As Employee In Employees.Values
tot += em.GetPay
Next
End Function
Function GetMessages(name As String) As List(Of Integer)
Return Employees(name).AllMessages
End Function
Function GetPay(name As String) As Decimal
Return Employees(name).GetPay()
End Function
Sub RemoveMessages(name As String, messages As Integer)
Employees(name).RemoveMessages(messages)
End Sub
Sub AddMesages(name As String, messages As Integer)
End Sub
Try
Catch ex As ArgumentException
MessageBox.Show("ERROR: " & em.Name & vbCrLf & ex.Message & vbCrLf & "NOT ADDED")
End If
End Try
End Sub
Function GetDecimal(s As String) As Decimal
Dim v As Decimal = 0@
If Decimal.TryParse(s, v) Then Return v
Return -1@
End Function
Function GetInteger(s As String) As Integer
Dim v As Integer = 0
If Integer.TryParse(s, v) Then Return v
Return 0
End Function

' ===============================
<Serializable> Class Employee
Property Name As String
Property Messages As New List(Of Integer)

Function GetPay() As Decimal
Dim tm As Decimal = Messages.Sum
Select Case tm
Case < 2500
Return tm * 0.018@
Case < 5000
Return tm * 0.024@
Case < 7500
Return tm * 0.03@
Case < 10000
Return tm * 0.035@
Case Else
Return tm * 0.04@
End Select
End Function
Function AllMessages() As List(Of Integer)
Return Messages
End Function