VB.net stopping a backgroundworker - vb.net

I want to create a button that could stop my background worker and end all the process it is working on.
Here is my sample backgroundworker code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Try
If BackgroundWorker1.IsBusy <> True Then
BackgroundWorker1.RunWorkerAsync()
End If
Catch ex As Exception
End Try
End Sub
Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim counter As Integer = 1
Do
'updated code with stop function----------------
BackgroundWorker1.WorkerSupportsCancellation = True
If BackgroundWorker1.CancellationPending Then
e.Cancel = True
ProgressBar1.Value = 0
Exit Do
End If
'updated code with stop function----------------
ListBox1.Items.Add(counter)
ProgressBar1.Value = ((counter - 1) / limit) * 100
counter = counter + 1
Loop While(counter <= 999999999999999999)
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As System.Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
Try
Catch ex As Exception
End Try
End Sub
Private Sub BackgroundWorker1_Completed(sender As System.Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
Try
Catch ex As Exception
End Try
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False
End Sub
'updated code with stop function----------------
Private Sub StopButton_Click(sender As Object, e As EventArgs) Handles StopButton.Click
If BackgroundWorker1.IsBusy Then
If BackgroundWorker1.WorkerSupportsCancellation Then
BackgroundWorker1.CancelAsync()
End If
End If
End Sub
'updated code with stop function----------------
I want to reset the loop and return the Progress Bar to 0% when i stop the backgroundworker.
Is this possible?
The code above has been updated and it is now working fine.
I have added this code inside my do loop:
BackgroundWorker1.WorkerSupportsCancellation = True
If BackgroundWorker1.CancellationPending Then
e.Cancel = True
ProgressBar1.Value = 0
Exit Do
End If
I created a button that stops the worker:
Private Sub StopButton_Click(sender As Object, e As EventArgs) Handles StopButton.Click
If BackgroundWorker1.IsBusy Then
If BackgroundWorker1.WorkerSupportsCancellation Then
BackgroundWorker1.CancelAsync()
End If
End If
End Sub

The Backgroundworker class has the method CancelAsync() which you need to call to cancel the execution of the bgw.
You need to set the Backgroundworker.WorkerSupportsCancellation property to true and inside the while loop you need to check the CancellationPending property wether the value is true which indicates a call to the CancelAsync() method.
If CancellationPending evaluates to true, you would ( which you should have done already ) call one of the overloaded ReportProgress() (Docu) methods to set your ProgressBar value to the desired value.
EDIT: You should set the Cancel property of the DoWorkEventArgs to true so you can check the Cancelled property of the RunWorkerCompletedEventArgs inside the RunworkerCompletedevent.
You also shouldn not access any controls which lives in the UI thread. You better use the ProgressChanged(Docu) event.
See: BackgroundWorker Docu

Public Class Form1
Private iVal As Integer = 0
Private Sub bgw_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgw.DoWork
For iVal = iVal To 100 Step 1
bgw.ReportProgress(iVal)
Threading.Thread.Sleep(99)
If (bgw.CancellationPending = True) Then
e.Cancel = True
Exit For
End If
Next
End Sub
Private Sub bgw_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgw.ProgressChanged
pbar.Value = e.ProgressPercentage
lblProgrss.Text = e.ProgressPercentage.ToString() & "%"
End Sub
Private Sub bgw_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted
If (e.Cancelled = True) Then
pic.Visible = False
pbar.Value = iVal
lblProgrss.Text = iVal & "%"
btnstart.Text = "Start"
btnstart.BackColor = Color.Green
Else
pic.Visible = False
btnstart.Text = "Start"
btnstart.BackColor = Color.Green
iVal = 0
End If
End Sub
Private Sub btnstart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnstart.Click
If (btnstart.Text = "Start") Then
btnstart.Text = "Stop"
btnstart.BackColor = Color.Red
pic.Visible = True
bgw.RunWorkerAsync()
Else
If (bgw.IsBusy = True) Then
btnstart.Text = "Start"
btnstart.BackColor = Color.Green
bgw.CancelAsync()
End If
End If
End Sub
End Class

Related

Backgroundworker Errors

I am trying to implement BackgroundWorker in my vb.net code. I understand you cannot update the UI from the background worker. Since when setting breakpoints in my code in the Backgroundworker.DoWork sub I would get
Me.Accessibility.Object threw an exception of type 'System.InvalidOperationException'
Message "Cross-thread operation not valid: Control 'FrmLoad' accessed from a thread other than the thread it was created on."
To try to understand why this was happening I copied the code EXACTLY from
https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.backgroundworker?view=netframework-4.7.2
and when setting a breakpoints again in the DoWork sub I get the same exception. I have tried several other microsoft code examples with the same issue. Is there something wrong with the code?
Imports System
Imports System.ComponentModel
Imports System.Windows.Forms
Namespace BackgroundWorkerSimple
Public Partial Class Form1
Inherits Form
Public Sub New()
InitializeComponent()
backgroundWorker1.WorkerReportsProgress = True
backgroundWorker1.WorkerSupportsCancellation = True
End Sub
Private Sub startAsyncButton_Click(ByVal sender As Object, ByVal e As EventArgs)
If backgroundWorker1.IsBusy <> True Then
backgroundWorker1.RunWorkerAsync()
End If
End Sub
Private Sub cancelAsyncButton_Click(ByVal sender As Object, ByVal e As EventArgs)
If backgroundWorker1.WorkerSupportsCancellation = True Then
backgroundWorker1.CancelAsync()
End If
End Sub
Private Sub backgroundWorker1_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
Dim worker As BackgroundWorker = TryCast(sender, BackgroundWorker)
For i As Integer = 1 To 10
If worker.CancellationPending = True Then
e.Cancel = True
Exit For
Else
System.Threading.Thread.Sleep(500)
worker.ReportProgress(i * 10)
End If
Next
End Sub
Private Sub backgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
resultLabel.Text = (e.ProgressPercentage.ToString() & "%")
End Sub
Private Sub backgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
If e.Cancelled = True Then
resultLabel.Text = "Canceled!"
ElseIf e.[Error] IsNot Nothing Then
resultLabel.Text = "Error: " & e.[Error].Message
Else
resultLabel.Text = "Done!"
End If
End Sub
End Class
End Namespace
It's not actually hindering the code from running, but I want to make sure that the thread is actually remaining safe.
That sample code is written in C#, and you apparently left out a function and it’s call:
// Set up the BackgroundWorker object by
// attaching event handlers.
private void InitializeBackgroundWorker()
{
backgroundWorker1.DoWork +=
new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(
backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged +=
new ProgressChangedEventHandler(
backgroundWorker1_ProgressChanged);
}
While this can be rewritten using addhandler, the vbish way to do this is to add a handles clause to you method declaration.
I believe this is what you are looking for:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitializeComponent()
BackgroundWorker1.WorkerReportsProgress = True
BackgroundWorker1.WorkerSupportsCancellation = True
End Sub
Private Sub startAsyncButton_Click(sender As Object, e As EventArgs) Handles btn_Start.Click
If Not BackgroundWorker1.IsBusy Then
BackgroundWorker1.RunWorkerAsync()
End If
End Sub
Private Sub cancelAsyncButton_Click(sender As Object, e As EventArgs) Handles btn_Cancel.Click
If BackgroundWorker1.WorkerSupportsCancellation = True Then
BackgroundWorker1.CancelAsync()
End If
End Sub
Private Sub backgroundWorker1_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'Dim worker As BackgroundWorker = TryCast(sender, BackgroundWorker)
For i As Integer = 1 To 10
If Not BackgroundWorker1.CancellationPending Then
System.Threading.Thread.Sleep(500)
BackgroundWorker1.ReportProgress(i * 10)
Else
e.Cancel = True
Exit For
End If
Next
End Sub
Private Sub backgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
resultLabel.Text = (e.ProgressPercentage.ToString() & "%")
End Sub
Private Sub backgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If e.Cancelled = True Then
resultLabel.Text = "Canceled!"
ElseIf e.Error IsNot Nothing Then
resultLabel.Text = "Error: " & e.[Error].Message
Else
resultLabel.Text = "Done!"
End If
End Sub
The main thing it looked like you were missing was the Handles Event for the Background1.ProgressChanged

vb.net background worker cancel not working

I'm having an issue where BackgroundWorker.CancelAsync() isn't working. I have WorkerSupportsCancellation set to TRUE. I am also polling BackgroundWorker1.CancellationPending in DoWork. Here is sample code of what I am trying to achieve. I have background worker looping through a time stamp and assigning a value to Measurement variable. I have a subroutine that queries the last reported Measurement variable and writes to listbox. After 5 loops I send BackgroundWorker.CancelAsync(). I can see the cancellation is pending, but it doesn't actually cancel the background worker. Is this a race condition?
Public Class Form1
Dim Measurement As String
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()
Delay(0.5)
For x = 1 To 5
ListBox1.Items.Add(Measurement)
ListBox1.TopIndex = ListBox1.Items.Count - 1
TextBox1.Text = BackgroundWorker1.CancellationPending
Delay(1)
Next
BackgroundWorker1.CancelAsync()
TextBox1.Text = BackgroundWorker1.CancellationPending
ListBox1.Items.Add("Cancel Pend: " & BackgroundWorker1.CancellationPending)
Delay(5)
ListBox1.Items.Add("Busy: " & BackgroundWorker1.IsBusy)
End Sub
Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
If BackgroundWorker1.CancellationPending = True Then
e.Cancel = True
BackgroundWorker1.Dispose()
Exit Sub
Else
Do
Measurement = Now()
Loop
End If
End Sub
End Class
You just need to move the check for the cancellation inside the Do...Loop otherwise it will be tested only at the start of the DoWork event handler and never after that
Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
If BackgroundWorker1.CancellationPending = True Then
e.Cancel = True
BackgroundWorker1.Dispose()
Else
Do
If BackgroundWorker1.CancellationPending = True Then
e.Cancel = True
BackgroundWorker1.Dispose()
Exit Do
Else
Measurement = Now()
End If
Loop
End if
End Sub

combobox multiple thread error

I have a problem with my code. I keep getting Multiple thread Error with backgroundworker, because of the combobox item display. Please look at my code below its a very simple code which I am planning to use on big scale, all I want it to do is "If item "1" selected show item "1" in label1. I can only assume that problem exists because Combobox runs in different thread....
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
BackgroundWorker1.runworkerasync()
BackgroundWorker1.WorkerReportsProgress = True
Me.Cursor = Cursors.WaitCursor 'Cursor changes to wait
End Sub
Public Structure controlwithtext
Public controlname As Control
Public text As String
Public Sub New(ByVal ctrl As Control, ByVal text As String)
Me.controlname = ctrl
Me.text = text
End Sub
End Structure
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
If comboBox1.SelectedItem = "1" then
BackgroundWorker1.ReportProgress(5, New controlwithtext(Label1, ComboBox1.SelectedItem))
End If
End Sub
Private Sub SetBackgroundWorker_ProgressChanged(ByVal sender As Object,
ByVal e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
If TypeOf e.UserState Is controlwithtext Then
Dim cwt As controlwithtext = CType(e.UserState, controlwithtext)
cwt.controlname.Text = cwt.text
End If
End Sub
Here's an example of how to read from and write to controls from the BackgroundWorker thread:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
While True
System.Threading.Thread.Sleep(250)
Dim selection As String = Me.Invoke(Function()
If Not IsNothing(ComboBox1.SelectedItem) Then
Return ComboBox1.SelectedItem.ToString
Else
Return String.Empty
End If
End Function).ToString
If selection = "1" Then
Me.Invoke(Sub()
Label1.Text = ComboBox1.SelectedItem.ToString
End Sub)
Else
Me.Invoke(Sub()
Label1.Text = "something else"
End Sub)
End If
End While
End Sub

Form doesn't update while running button click event

I'm trying to update a progress bar at the end of each method in Visual Basic, the problem is that label1.Text does not update itself at the start at each method but will update.
Public Class Form2
Private Const METHOD_COUNT = 4
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ProgressBar1.Maximum = METHOD_COUNT
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Method_One()
Method_Two()
Method_Three()
Method_Four()
End Sub
Private Sub Method_One()
Label1.Text = "Loading Method One"
ProgressBar1.Value += 1
'Threading.Thread.Sleep(1000)
End Sub
Private Sub Method_Two()
Label1.Text = "Loading Method Two"
ProgressBar1.Value += 1
'Threading.Thread.Sleep(1000)
End Sub
Private Sub Method_Three()
Label1.Text = "Loading Method Three"
ProgressBar1.Value += 1
'Threading.Thread.Sleep(1000)
End Sub
Private Sub Method_Four()
Label1.Text = "Loading Method Four"
ProgressBar1.Value += 1
'Threading.Thread.Sleep(1000)
End Sub
End Class
So basically when you run this, it will execute and update the progress bar nicely, but the label does not update. I think it might have something to do with multithreading and the fact the form does not get a constant update.
The "quick fix" is to add Application.DoEvents() before each call to Sleep():
Public Class Form2
Private Const METHOD_COUNT = 4
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ProgressBar1.Maximum = METHOD_COUNT
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Method_One()
Method_Two()
Method_Three()
Method_Four()
End Sub
Private Sub Method_One()
Label1.Text = "Loading Method One"
ProgressBar1.Value += 1
Application.DoEvents()
Threading.Thread.Sleep(1000)
End Sub
Private Sub Method_Two()
Label1.Text = "Loading Method Two"
ProgressBar1.Value += 1
Application.DoEvents()
Threading.Thread.Sleep(1000)
End Sub
Private Sub Method_Three()
Label1.Text = "Loading Method Three"
ProgressBar1.Value += 1
Application.DoEvents()
Threading.Thread.Sleep(1000)
End Sub
Private Sub Method_Four()
Label1.Text = "Loading Method Four"
ProgressBar1.Value += 1
Application.DoEvents()
Threading.Thread.Sleep(1000)
End Sub
End Class
The "correct fix" is that your "work" should not be done in the main UI thread, which is what you're doing be calling those methods from the button click handler. Instead, you need to move the work to a background thread so that the UI can update itself. Take a look at using the BackgroundWorker() control. You call its ReportProgress() method which fires the ProgressChanged() event. From that event it's safe to update the UI. When the work in the background thread is complete you'll get a RunWorkerCompleted() event. Note that you have to set the WorkerReportsProgress() property to True if you want to use the progress events:
Public Class Form2
Private Const METHOD_COUNT = 4
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ProgressBar1.Maximum = METHOD_COUNT
BackgroundWorker1.WorkerReportsProgress = True
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If Not BackgroundWorker1.IsBusy Then
Button1.Enabled = False
BackgroundWorker1.RunWorkerAsync()
End If
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Method_One()
Method_Two()
Method_Three()
Method_Four()
End Sub
Private Sub Method_One()
BackgroundWorker1.ReportProgress(1, "Loading Method One")
Threading.Thread.Sleep(1000)
End Sub
Private Sub Method_Two()
BackgroundWorker1.ReportProgress(2, "Loading Method Two")
Threading.Thread.Sleep(1000)
End Sub
Private Sub Method_Three()
BackgroundWorker1.ReportProgress(3, "Loading Method Three")
Threading.Thread.Sleep(1000)
End Sub
Private Sub Method_Four()
BackgroundWorker1.ReportProgress(4, "Loading Method Four")
Threading.Thread.Sleep(1000)
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
Label1.Text = e.UserState
ProgressBar1.Value = e.ProgressPercentage
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
Button1.Enabled = True
MessageBox.Show("Done!")
End Sub
End Class
If you think the value of the label is being changed, but the screen is not being updated have you tried the refresh method?
For example:
Private Sub Method_Three()
Label1.Text = "Loading Method Three"
Label1.Refresh
ProgressBar1.Value += 1
'Threading.Thread.Sleep(1000)
End Sub
I am sure someone else can explain why this is but i have always had to use the following to get Labels to update when they wouldn't otherwise:
Private Sub Method_Three()
With Label1
.Text = "Loading Method Three"
.Refresh
End With
ProgressBar1.Value += 1
'Threading.Thread.Sleep(1000)
End Sub

Disable Button until multiple Textboxes got Validated

I have a form with over 10 textboxes and 1 button, I would like to disable the button with a realtime validation until all textboxes filled with a 10 or a 13 length numeric value, my code is the following so far:
Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
For Each userID As Control In Me.Controls.OfType(Of TextBox)()
AddHandler userID.TextChanged, AddressOf ValidateAllFields
Next userID
End Sub
Private Sub userID_KeyPress(ByVal sender As Object, ByVal e As KeyPressEventArgs) Handles Me.KeyPress
If e.KeyChar <> ChrW(Keys.Back) Then
If Char.IsNumber(e.KeyChar) Then
Else
e.Handled = True
End If
End If
End Sub
Private Function ValidateAllFields()
Dim Validation As Boolean = True
For Each userID As Control In Me.Controls.OfType(Of TextBox)()
Dim e As New System.ComponentModel.CancelEventArgs
e.Cancel = False
Call userID_Validating(userID, e)
If e.Cancel = True Then Validation = False
Next userID
buttonSave.Enabled = Not Me.Controls.OfType(Of TextBox).Any(Function(userID) userID.Text.Length <> 10 AndAlso userID.Text.Length <> 13)
Return Validation
End Function
Private Sub userID_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles _
user00.Validating, _
user01.Validating, _
user02.Validating, _
user03.Validating, _
user04.Validating, _
user05.Validating, _
user06.Validating, _
user07.Validating, _
user07.Validating, _
user08.Validating, _
user09.Validating, _
user10.Validating, _
user11.Validating
If Not IsNumeric(sender.Text) OrElse (sender.Text.Length <> 10) AndAlso (sender.Text.Length <> 13) Then
ErrorProvider1.SetError(sender, "")
ErrorProvider2.SetError(sender, "Please enter a valid User ID.")
e.Cancel = True
Else
ErrorProvider1.SetError(sender, "Valid User ID.")
ErrorProvider2.SetError(sender, "")
End If
End Sub
Thanks to your help it works as I wanted, but can you help me improve/clean it? I'm still studying vb, I'm open to any suggestion. Thanks in advance!
Here you have a code performing the actions you want:
Dim done1, done2, done3 As Boolean
Dim targetLength1 As Integer = 10
Dim targetLength2 As Integer = 13
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged
Try
If (IsNumeric(TextBox1.Text)) Then
If (TextBox1.Text.Length = targetLength1 Or TextBox1.Text.Length = targetLength2) Then
done1 = True
End If
End If
If (done1 And done2 And done3) Then
Button1.Enabled = True
End If
Catch ex As Exception
End Try
End Sub
Private Sub TextBox2_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox2.TextChanged
Try
If (IsNumeric(TextBox2.Text)) Then
If (TextBox2.Text.Length = targetLength1 Or TextBox2.Text.Length = targetLength2) Then
done2 = True
End If
End If
If (done1 And done2 And done3) Then
Button1.Enabled = True
End If
Catch ex As Exception
End Try
End Sub
Private Sub TextBox3_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox3.TextChanged
Try
If (IsNumeric(TextBox3.Text)) Then
If (TextBox3.Text.Length = targetLength1 Or TextBox3.Text.Length = targetLength2) Then
done3 = True
End If
End If
If (done1 And done2 And done3) Then
Button1.Enabled = True
End If
Catch ex As Exception
End Try
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Button1.Enabled = False
End Sub
It accounts just for 3 textboxes (TextBox1, TextBox2 and TextBox3) and 1 button (Button1) but you can extend the idea to as many textboxes as you wish. It relies on the TextChanged even of each textbox. When the condition is met (given textbox has a number whose length is 10 or 13), the corresponding flag is set to true (e.g., done1 for TextBox1...). When all the flags are true (all the textboxes contain the expected information), the button is disabled.
I think would better to use TextChanged Event ..
Private Sub TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged, TextBox2.TextChanged, ....., TextBox10.TextChanged
Chk4ButtonEnabled()
End Sub
Sub Chk4ButtonEnabled()
Dim s as String
For Each userID As Control In Me.Controls
If userID.GetType Is GetType(TextBox) Then
s = userID.Text
If Not s.Length = 10 OR Not s.Length = 13 Then
ErrorProvider1.SetError(userID, "")
buttonSave.Enabled = False
Else
ErrorProvider1.SetError(userID, "Valid User ID.")
buttonSave.Enabled = True
End If
End If
Next
End Sub