| | |
VB.NET Threading or Backgroundworker ?? Struggling to get them to work
Please support our VB.NET advertiser: Intel Parallel Studio Home
![]() |
•
•
Join Date: Jan 2008
Posts: 16
Reputation:
Solved Threads: 0
Hi
I've developed an app that reads in a csv file, strips it out to its component fields, validates them and writes it up to the database.
So far, so good.
I now want to enhance it so that the dataloading take place in the background enabling the UI to be used for some progress indication when loading large files.
I've managed to get the loading working in both a thread and backgroundworker but have not managed to do anything successful with the UI. I've read numerous posts on the net, which seem to make sense but I can't see how to apply them to my "real world" situation.
If I use a thread, I can't do anything with the controls on the form as they belong to another thread. When I tried the backgroundworker, the UI still appears to be frozen.
So I've stripped all that code out and my app is running on the single thread again.
I've tried to keep the code on the form to just the visual effects calling methods in another class to do the data reading, manipulation, validation and loading.
Any help would be greatly appreciated, as I just can't get it to do what I need.
Regards
Andrew
I've developed an app that reads in a csv file, strips it out to its component fields, validates them and writes it up to the database.
So far, so good.
I now want to enhance it so that the dataloading take place in the background enabling the UI to be used for some progress indication when loading large files.
I've managed to get the loading working in both a thread and backgroundworker but have not managed to do anything successful with the UI. I've read numerous posts on the net, which seem to make sense but I can't see how to apply them to my "real world" situation.
If I use a thread, I can't do anything with the controls on the form as they belong to another thread. When I tried the backgroundworker, the UI still appears to be frozen.
So I've stripped all that code out and my app is running on the single thread again.
I've tried to keep the code on the form to just the visual effects calling methods in another class to do the data reading, manipulation, validation and loading.
Any help would be greatly appreciated, as I just can't get it to do what I need.
Regards
Andrew
In the code of your UI try using
AddHandler objFileIOClass.Event, AddressOf UIClass.Function
where FileIOClass.Event is the Event Raised from the FileIOClass and UIClass.Function is the Address of the function you want to execute in the UI when the Event is raised. It should look something like this:
Dim objFileIOClass as New FileIOClass
AddHandler objFileIOClass .Event, AddressOf UIClass.Function
Dim FileIOThread = New Threading.Thread(AddressOf FileIOClass.BeginOperation)
FileIOThread.Start()
AddHandler objFileIOClass.Event, AddressOf UIClass.Function
where FileIOClass.Event is the Event Raised from the FileIOClass and UIClass.Function is the Address of the function you want to execute in the UI when the Event is raised. It should look something like this:
Dim objFileIOClass as New FileIOClass
AddHandler objFileIOClass .Event, AddressOf UIClass.Function
Dim FileIOThread = New Threading.Thread(AddressOf FileIOClass.BeginOperation)
FileIOThread.Start()
•
•
Join Date: Jan 2008
Posts: 16
Reputation:
Solved Threads: 0
Hi
Thanks for the help so far, but I'm still struggling with this I'm afraid.
I have the "lengthy process" running in a thread that is called from a button click on the front end main form (UI).
I raise an event at the end of the "lengthy process", but the event handler wont do everything that I need it to because it errors saying the controls I am trying to update belong to another thread.
The "lengthy process" is in a seperate class from the frm.vb code.
Thanks
Andrew
Thanks for the help so far, but I'm still struggling with this I'm afraid.
I have the "lengthy process" running in a thread that is called from a button click on the front end main form (UI).
I raise an event at the end of the "lengthy process", but the event handler wont do everything that I need it to because it errors saying the controls I am trying to update belong to another thread.
The "lengthy process" is in a seperate class from the frm.vb code.
Thanks
Andrew
•
•
Join Date: Jan 2008
Posts: 16
Reputation:
Solved Threads: 0
Code for my button click event.
THis is the code I'm trying to run in the event handler when the lengthy process finishes. It fails when I try to do anything with the cursor or labels/ textboxes / buttons etc. on the form.
Thanks
Andrew
vb Syntax (Toggle Plain Text)
Private Sub btnGo1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGo1.Click aiidb2.ExcludeDuplicates = False If (txtDelim1.Text = "") Then MessageBox.Show("You MUST enter a field delimiter for the CSV input file") txtDelim1.Focus() GoTo lab_end End If If (txtAimsNo.Text = "") Then MessageBox.Show("You MUST enter an AIMS number for the input file") txtAimsNo.Focus() GoTo lab_end End If If (txtReceiptNo.Text = "") Then MessageBox.Show("You MUST enter a contractor receipt number for the input file") txtReceiptNo.Focus() GoTo lab_end End If If aiidb2.DuplicatesFound Then Dim dlgRes As DialogResult dlgRes = MessageBox.Show( _ "This contractor return contains duplicate rows." + vbCr + vbLf + _ "Do you want to load the duplicates into SOURCEData?", "File Contains Duplicate Rows", _ MessageBoxButtons.YesNoCancel, _ MessageBoxIcon.Question) If dlgRes = Windows.Forms.DialogResult.Yes Then aiidb2.ExcludeDuplicates = False ElseIf dlgRes = Windows.Forms.DialogResult.No Then aiidb2.ExcludeDuplicates = True Else GoTo lab_end End If End If ' Get current date/time and format it aiidb2.GetDateTime() aiidb2.FormatDateTime() aiidb2.NowDate = aiidb2.Now.Year.ToString + aiidb2.NowMonth + aiidb2.NowDay aiidb2.NowTime = aiidb2.NowHour + aiidb2.NowMinute If aiidb2.ExcludeDuplicates Then 'Create file of duplicates aiidb2.DuplicatesFile() End If ' ***** Initialise variables aiidb2.ErrorRate = 0 'Test if replayed error file If (aiidb2.ErrorFile) Then If MessageBox.Show("This is an error file." + vbCr + vbLf + _ "Has it been corrected?" + vbCr + vbLf + _ "Are you sure you want to replay this error file?", "Error File", _ MessageBoxButtons.YesNo, MessageBoxIcon.Question) _ = Windows.Forms.DialogResult.Yes Then 'do Nothing Else GoTo lab_end End If End If aiidb2.CreateOriginalFileName() Me.Cursor = Cursors.WaitCursor ' Call to the lengthy process here 'Dim t As New Thread(AddressOf aiidb2.LoadData) 'AddHandler aiidb2.FinishedDataLoading, AddressOf FinishedDataLoadingEventHandler 't.Start() lab_end: End Sub
THis is the code I'm trying to run in the event handler when the lengthy process finishes. It fails when I try to do anything with the cursor or labels/ textboxes / buttons etc. on the form.
vb Syntax (Toggle Plain Text)
'If no errors, tidy files up If (aiidb2.ErrorCount = 0) Then 'Archive orignal file here File.Move(aiidb2.FilePath + aiidb2.OriginalFileName, aiidb2.FilePathArchived + aiidb2.OriginalFileName) ' TODO: Possibly set DataLoadRequired flag on DB to false after successful load ' TODO: Business decision on whether to delete replayed / corrected errorfile or Archive ' Currently archive the file ' ***** DELETE ErrorFile ***** 'Delete replayed error file (this can be reintroduced if neccessary, decided to keep corrected error file) 'If (aiidb2.errorFile) Then 'File.Delete(filePath + FileName) 'End If ' ***** ARCHIVE ErrorFile ***** 'Archive replayed / corrected errorfile If (aiidb2.ErrorFile) Then File.Move(aiidb2.FileName, aiidb2.FilePathArchived + aiidb2.FileNameNoPath) End If 'MessageBox.Show("Original RAW data archived & any replayed error file deleted") End If 'Calculate error rate as percentage aiidb2.ErrorRate = Math.Round(((aiidb2.ErrorCount / aiidb2.EndCount) * 100), 2) Me.Cursor = Cursors.Default If (aiidb2.DuplicatesFound And aiidb2.ExcludeDuplicates) Then MessageBox.Show(aiidb2.SuccessCount & " Rows Inserted into SOURCEData" & vbCr & vbLf & vbCr & vbLf & aiidb2.Dups.Count.ToString & " Rows written to DUPLICATES file" & vbCr & vbLf & vbCr & vbLf & aiidb2.ErrorCount & " Rows written to ERROR file" & vbCr & vbLf & vbCr & vbLf & "Error rate: " & aiidb2.ErrorRate & "%", "Load Summary") Else MessageBox.Show(aiidb2.SuccessCount & " Rows Inserted into SOURCEData" & vbCr & vbLf & vbCr & vbLf & aiidb2.ErrorCount & " Rows written to ERROR file" & vbCr & vbLf & vbCr & vbLf & "Error rate: " & aiidb2.ErrorRate & "%", "Load Summary") End If lblFilename1.Visible = False lblFilename1.Text = Nothing aiidb2.FileName = Nothing lblDelim1.Visible = False lblAimsNo.Visible = False lblReceiptNo.Visible = False txtDelim1.Visible = False txtAimsNo.Text = "" txtAimsNo.Visible = False txtReceiptNo.Text = "" txtReceiptNo.Visible = False btnBrowseData.Visible = False btnGo1.Visible = False panData.Visible = False
Thanks
Andrew
Apparently, I have given you bad advice. The solution I presented appears to no longer be supported. The following is a comprehensive view of updating a UI from another thread and also using the background worker. This is an actual program that demonstrates the concepts. You can start a new Windows Application Project and paste the code in the code-behind of Form1. If you get build errors, delete the code from the Form1.Designer.vb file.
VB.NET Syntax (Toggle Plain Text)
Imports System Imports System.ComponentModel Imports System.Threading Imports System.Windows.Forms Public Class Form1 Inherits Form ' This delegate enables asynchronous calls for setting ' the text property on a TextBox control. Delegate Sub SetTextCallback([text] As String) ' This thread is used to demonstrate both thread-safe and ' unsafe ways to call a Windows Forms control. Private demoThread As Thread = Nothing ' This BackgroundWorker is used to demonstrate the ' preferred way of performing asynchronous operations. Private WithEvents backgroundWorker1 As BackgroundWorker Private textBox1 As TextBox Private WithEvents setTextUnsafeBtn As Button Private WithEvents setTextSafeBtn As Button Private WithEvents setTextBackgroundWorkerBtn As Button Private components As System.ComponentModel.IContainer = Nothing Public Sub New() InitializeComponent() End Sub Protected Overrides Sub Dispose(disposing As Boolean) If disposing AndAlso (components IsNot Nothing) Then components.Dispose() End If MyBase.Dispose(disposing) End Sub ' This event handler creates a thread that calls a ' Windows Forms control in an unsafe way. Private Sub setTextUnsafeBtn_Click( _ ByVal sender As Object, _ ByVal e As EventArgs) Handles setTextUnsafeBtn.Click Me.demoThread = New Thread( _ New ThreadStart(AddressOf Me.ThreadProcUnsafe)) Me.demoThread.Start() End Sub ' This method is executed on the worker thread and makes ' an unsafe call on the TextBox control. Private Sub ThreadProcUnsafe() Me.textBox1.Text = "This text was set unsafely." End Sub ' This event handler creates a thread that calls a ' Windows Forms control in a thread-safe way. Private Sub setTextSafeBtn_Click( _ ByVal sender As Object, _ ByVal e As EventArgs) Handles setTextSafeBtn.Click Me.demoThread = New Thread( _ New ThreadStart(AddressOf Me.ThreadProcSafe)) Me.demoThread.Start() End Sub ' This method is executed on the worker thread and makes ' a thread-safe call on the TextBox control. Private Sub ThreadProcSafe() Me.SetText("This text was set safely.") End Sub ' This method demonstrates a pattern for making thread-safe ' calls on a Windows Forms control. ' ' If the calling thread is different from the thread that ' created the TextBox control, this method creates a ' SetTextCallback and calls itself asynchronously using the ' Invoke method. ' ' If the calling thread is the same as the thread that created ' the TextBox control, the Text property is set directly. Private Sub SetText(ByVal [text] As String) ' InvokeRequired required compares the thread ID of the ' calling thread to the thread ID of the creating thread. ' If these threads are different, it returns true. If Me.textBox1.InvokeRequired Then Dim d As New SetTextCallback(AddressOf SetText) Me.Invoke(d, New Object() {[text]}) Else Me.textBox1.Text = [text] End If End Sub ' This event handler starts the form's ' BackgroundWorker by calling RunWorkerAsync. ' ' The Text property of the TextBox control is set ' when the BackgroundWorker raises the RunWorkerCompleted ' event. Private Sub setTextBackgroundWorkerBtn_Click( _ ByVal sender As Object, _ ByVal e As EventArgs) Handles setTextBackgroundWorkerBtn.Click Me.backgroundWorker1.RunWorkerAsync() End Sub ' This event handler sets the Text property of the TextBox ' control. It is called on the thread that created the ' TextBox control, so the call is thread-safe. ' ' BackgroundWorker is the preferred way to perform asynchronous ' operations. Private Sub backgroundWorker1_RunWorkerCompleted( _ ByVal sender As Object, _ ByVal e As RunWorkerCompletedEventArgs) _ Handles backgroundWorker1.RunWorkerCompleted Me.textBox1.Text = _ "This text was set safely by BackgroundWorker." End Sub #Region "Windows Form Designer generated code" Private Sub InitializeComponent() Me.textBox1 = New System.Windows.Forms.TextBox() Me.setTextUnsafeBtn = New System.Windows.Forms.Button() Me.setTextSafeBtn = New System.Windows.Forms.Button() Me.setTextBackgroundWorkerBtn = New System.Windows.Forms.Button() Me.backgroundWorker1 = New System.ComponentModel.BackgroundWorker() Me.SuspendLayout() ' ' textBox1 ' Me.textBox1.Location = New System.Drawing.Point(12, 12) Me.textBox1.Name = "textBox1" Me.textBox1.Size = New System.Drawing.Size(240, 20) Me.textBox1.TabIndex = 0 ' ' setTextUnsafeBtn ' Me.setTextUnsafeBtn.Location = New System.Drawing.Point(15, 55) Me.setTextUnsafeBtn.Name = "setTextUnsafeBtn" Me.setTextUnsafeBtn.TabIndex = 1 Me.setTextUnsafeBtn.Text = "Unsafe Call" ' ' setTextSafeBtn ' Me.setTextSafeBtn.Location = New System.Drawing.Point(96, 55) Me.setTextSafeBtn.Name = "setTextSafeBtn" Me.setTextSafeBtn.TabIndex = 2 Me.setTextSafeBtn.Text = "Safe Call" ' ' setTextBackgroundWorkerBtn ' Me.setTextBackgroundWorkerBtn.Location = New System.Drawing.Point(177, 55) Me.setTextBackgroundWorkerBtn.Name = "setTextBackgroundWorkerBtn" Me.setTextBackgroundWorkerBtn.TabIndex = 3 Me.setTextBackgroundWorkerBtn.Text = "Safe BW Call" ' ' backgroundWorker1 ' ' ' Form1 ' Me.ClientSize = New System.Drawing.Size(268, 96) Me.Controls.Add(setTextBackgroundWorkerBtn) Me.Controls.Add(setTextSafeBtn) Me.Controls.Add(setTextUnsafeBtn) Me.Controls.Add(textBox1) Me.Name = "Form1" Me.Text = "Form1" Me.ResumeLayout(False) Me.PerformLayout() End Sub 'InitializeComponent #End Region <STAThread()> _ Shared Sub Main() Application.EnableVisualStyles() Application.Run(New Form1()) End Sub End Class
![]() |
Other Threads in the VB.NET Forum
- Previous Thread: Randomize A Chosen
- Next Thread: Enable Menu items
| Thread Tools | Search this Thread |
.net .net2005 30minutes 2005 2008 access account arithmetic array basic binary bing button buttons center check code combobox component connectionstring crystalreport data database databasesearch datagrid datagridview date design dissertation dissertations dissertationthesis dropdownlist excel fade file-dialog folder ftp generatetags google gridview hardcopy image images input insert intel internet mobile monitor ms net networking objects output passingparameters peertopeervideostreaming picturebox picturebox1 port print problem problemwithinstallation project reports" save savedialog searchbox searchvb.net select serial shutdown soap survey table tcp temperature text textbox timer toolbox trim update updown user usercontrol vb vb.net vb.netcode vb.netformclosing()eventpictureboxmessagebox vb2008 vbnet view visual visualbasic visualbasic.net visualstudio visualstudio2008 web winforms wpf





