Hi
I am running a background worker that continually updates a list. The interval is determined by a NumericUpDown on the UI.
If I alter the interval whilst the background is working I get a cross-threading error.
I understand I can send an argument when starting the background worker in the format RunWorkerAsync(arg) but could someone just clarify how to use that?
Do I need to set a separate class for the argument value or can I just use RunWorkerAsync(myInterval.value) and then get the value as e.argument in the DoWork?
In short, how do I get the following idea to work? -
BackgroundWorker1.RunWorkerAsync(myInterval.value)
-
-
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
-
Dim checkcount As Integer = 0
-
Do checkcount += 1
-
BackgroundWorker1.ReportProgress(checkcount)
-
Threading.Thread.Sleep(e.Argument * 1000)
-
If BackgroundWorker1.CancellationPending = True Then Exit Do
-
Loop
-
End Sub
-
Thanks
You don't need a class to change the value but you do need a variable that is accessible to all threads.
In my example, the variable is an integer and because it is a native type/not a reference type I do not need to use SyncLock on the item to prevent cross threading issues. Please note that any variables that are Objects (classes) will require you to uses a SyncLock block around them to prevent issues where threads are trying to update the same value at the same time. Also be aware that you could result in a deadlock if too many threads are going at the same time and all of them are SyncLocking the common variables.
Anyways, here's an example!
I have created a WPF project which has one window in it called MainWindow. On the MainWindow I have defined: - a ComboBox used to set the sleep timer value and also used to stop the background work if 0 is selected
- a TextBlock (a control similar to a win form's label) that is used to display results that the background work will produce
Here is the XML code for the window: -
<Window x:Class="MainWindow"
-
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-
Title="MainWindow" Height="350" Width="525"
-
xmlns:local="clr-namespace:PracticeProject">
-
<Grid>
-
<Grid.RowDefinitions>
-
<RowDefinition Height="Auto"/>
-
<RowDefinition Height="Auto" />
-
</Grid.RowDefinitions>
-
<TextBlock x:Name="StatusMessage" Text="" Grid.Row="0" />
-
<ComboBox x:Name="MyInterval" Grid.Row="1"
-
SelectedIndex="0"
-
SelectionChanged="MyInterval_SelectionChanged">
-
<ComboBox.Items>
-
<ComboBoxItem>0</ComboBoxItem>
-
<ComboBoxItem>5</ComboBoxItem>
-
<ComboBoxItem>8</ComboBoxItem>
-
<ComboBoxItem>10</ComboBoxItem>
-
</ComboBox.Items>
-
</ComboBox>
-
</Grid>
-
</Window>
In the VB.NET code for the MainWindow I have 2 private members defined: a background worker, the value selected that is shared across all background worker threads to indicate the interval that should be used.
I have a method that handles the ComboBox's SelectionChanged event.
In that method I: - set the selected interval value
- create a new background worker if one hasn't been created and begin the process
- stop the background worker if the value selected is 0 (please note that the process will be stopped as soon as the current sleep timer elapses and the thread detects the cancellation)
I have a Do Work method that does the same thing as your method but also calls a methods to print things to the screen so that I can demonstrate what is going on and I have a completed method that is similar to yours as well.
Here is the VB.NET code: -
Class MainWindow
-
Private Delegate Sub ErrorCreateSource(ByVal msg As String)
-
Private waitingBackgroundWorker As System.ComponentModel.BackgroundWorker = Nothing ' used to do the work
-
Private valueSelected As Integer ' indicates the sleep interval value selected
-
-
Private Sub MyInterval_SelectionChanged(sender As System.Object, e As System.Windows.Controls.SelectionChangedEventArgs)
-
'Here I would have to use a SyncLock if I wasn't using an Integer type
-
'to pass information to the background worker process in order to prevent multiple things
-
'from setting the value in the middle of processing
-
-
'Attempting to parse the item selected into the valueSelected variable (if I can't I stop the process)
-
'And checking to make sure the value is greater than 0 (my stop case is when I select 0)
-
If Integer.TryParse(DirectCast(DirectCast(sender, ComboBox).SelectedItem, ComboBoxItem).Content, valueSelected) AndAlso valueSelected > 0 Then
-
-
If waitingBackgroundWorker Is Nothing Then
-
' we do not have a background worker yet: creating one and starting it
-
waitingBackgroundWorker = New System.ComponentModel.BackgroundWorker
-
waitingBackgroundWorker.WorkerReportsProgress = True
-
waitingBackgroundWorker.WorkerSupportsCancellation = True
-
AddHandler waitingBackgroundWorker.DoWork, AddressOf WaitBackgroundWorker_DoWork 'the method that is used to do the work
-
AddHandler waitingBackgroundWorker.RunWorkerCompleted, AddressOf WaitBackgroundWorker_RunWorkerCompleted ' the method that is used when work is completed
-
waitingBackgroundWorker.RunWorkerAsync() 'staring the process
-
End If
-
Else
-
'Either the values selected was not a number or the value selected was 0
-
If waitingBackgroundWorker IsNot Nothing Then
-
waitingBackgroundWorker.CancelAsync()
-
End If
-
End If
-
End Sub
-
Private Sub WaitBackgroundWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
-
Dim checkcount As Integer = 0
-
Dim oldTimer = valueSelected
-
Do
-
checkcount += 1
-
sender.ReportProgress(checkcount)
-
System.Threading.Thread.Sleep(valueSelected * 1000)
-
If sender.CancellationPending = True Then Exit Do
-
UpdateUI(String.Format("Continuing: {0}old timer value: {1} {0}new timer value: {2} {0}iteration: {3}", System.Environment.NewLine, oldTimer.ToString, valueSelected.ToString, checkcount.ToString))
-
Loop
-
e.Result = String.Format("{0}Reults: {0}old timer value: {1} {0}new timer value: {2} {0}iteration: {3}", System.Environment.NewLine, oldTimer.ToString, valueSelected.ToString, checkcount.ToString)
-
End Sub
-
Private Sub WaitBackgroundWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As ComponentModel.RunWorkerCompletedEventArgs)
-
UpdateUI(e.Result)
-
UpdateUI(String.Format("Completed! {0} ", e.Result))
-
CType(sender, System.ComponentModel.BackgroundWorker).Dispose()
-
waitingBackgroundWorker = Nothing
-
End Sub
-
Sub UpdateUI(ByVal msg As String)
-
Dim uiHandler As New ErrorCreateSource(AddressOf UpdateUIIndicatorsMsg)
-
Me.Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Normal, uiHandler, msg)
-
End Sub
-
Sub UpdateUIIndicatorsMsg(ByVal msg As String)
-
StatusMessage.Text = msg
-
End Sub
-
End Class
I think the code is self explanatory, but if you have questions please ask!
-Frinny
3 1295
You don't need a class to change the value but you do need a variable that is accessible to all threads.
In my example, the variable is an integer and because it is a native type/not a reference type I do not need to use SyncLock on the item to prevent cross threading issues. Please note that any variables that are Objects (classes) will require you to uses a SyncLock block around them to prevent issues where threads are trying to update the same value at the same time. Also be aware that you could result in a deadlock if too many threads are going at the same time and all of them are SyncLocking the common variables.
Anyways, here's an example!
I have created a WPF project which has one window in it called MainWindow. On the MainWindow I have defined: - a ComboBox used to set the sleep timer value and also used to stop the background work if 0 is selected
- a TextBlock (a control similar to a win form's label) that is used to display results that the background work will produce
Here is the XML code for the window: -
<Window x:Class="MainWindow"
-
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-
Title="MainWindow" Height="350" Width="525"
-
xmlns:local="clr-namespace:PracticeProject">
-
<Grid>
-
<Grid.RowDefinitions>
-
<RowDefinition Height="Auto"/>
-
<RowDefinition Height="Auto" />
-
</Grid.RowDefinitions>
-
<TextBlock x:Name="StatusMessage" Text="" Grid.Row="0" />
-
<ComboBox x:Name="MyInterval" Grid.Row="1"
-
SelectedIndex="0"
-
SelectionChanged="MyInterval_SelectionChanged">
-
<ComboBox.Items>
-
<ComboBoxItem>0</ComboBoxItem>
-
<ComboBoxItem>5</ComboBoxItem>
-
<ComboBoxItem>8</ComboBoxItem>
-
<ComboBoxItem>10</ComboBoxItem>
-
</ComboBox.Items>
-
</ComboBox>
-
</Grid>
-
</Window>
In the VB.NET code for the MainWindow I have 2 private members defined: a background worker, the value selected that is shared across all background worker threads to indicate the interval that should be used.
I have a method that handles the ComboBox's SelectionChanged event.
In that method I: - set the selected interval value
- create a new background worker if one hasn't been created and begin the process
- stop the background worker if the value selected is 0 (please note that the process will be stopped as soon as the current sleep timer elapses and the thread detects the cancellation)
I have a Do Work method that does the same thing as your method but also calls a methods to print things to the screen so that I can demonstrate what is going on and I have a completed method that is similar to yours as well.
Here is the VB.NET code: -
Class MainWindow
-
Private Delegate Sub ErrorCreateSource(ByVal msg As String)
-
Private waitingBackgroundWorker As System.ComponentModel.BackgroundWorker = Nothing ' used to do the work
-
Private valueSelected As Integer ' indicates the sleep interval value selected
-
-
Private Sub MyInterval_SelectionChanged(sender As System.Object, e As System.Windows.Controls.SelectionChangedEventArgs)
-
'Here I would have to use a SyncLock if I wasn't using an Integer type
-
'to pass information to the background worker process in order to prevent multiple things
-
'from setting the value in the middle of processing
-
-
'Attempting to parse the item selected into the valueSelected variable (if I can't I stop the process)
-
'And checking to make sure the value is greater than 0 (my stop case is when I select 0)
-
If Integer.TryParse(DirectCast(DirectCast(sender, ComboBox).SelectedItem, ComboBoxItem).Content, valueSelected) AndAlso valueSelected > 0 Then
-
-
If waitingBackgroundWorker Is Nothing Then
-
' we do not have a background worker yet: creating one and starting it
-
waitingBackgroundWorker = New System.ComponentModel.BackgroundWorker
-
waitingBackgroundWorker.WorkerReportsProgress = True
-
waitingBackgroundWorker.WorkerSupportsCancellation = True
-
AddHandler waitingBackgroundWorker.DoWork, AddressOf WaitBackgroundWorker_DoWork 'the method that is used to do the work
-
AddHandler waitingBackgroundWorker.RunWorkerCompleted, AddressOf WaitBackgroundWorker_RunWorkerCompleted ' the method that is used when work is completed
-
waitingBackgroundWorker.RunWorkerAsync() 'staring the process
-
End If
-
Else
-
'Either the values selected was not a number or the value selected was 0
-
If waitingBackgroundWorker IsNot Nothing Then
-
waitingBackgroundWorker.CancelAsync()
-
End If
-
End If
-
End Sub
-
Private Sub WaitBackgroundWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
-
Dim checkcount As Integer = 0
-
Dim oldTimer = valueSelected
-
Do
-
checkcount += 1
-
sender.ReportProgress(checkcount)
-
System.Threading.Thread.Sleep(valueSelected * 1000)
-
If sender.CancellationPending = True Then Exit Do
-
UpdateUI(String.Format("Continuing: {0}old timer value: {1} {0}new timer value: {2} {0}iteration: {3}", System.Environment.NewLine, oldTimer.ToString, valueSelected.ToString, checkcount.ToString))
-
Loop
-
e.Result = String.Format("{0}Reults: {0}old timer value: {1} {0}new timer value: {2} {0}iteration: {3}", System.Environment.NewLine, oldTimer.ToString, valueSelected.ToString, checkcount.ToString)
-
End Sub
-
Private Sub WaitBackgroundWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As ComponentModel.RunWorkerCompletedEventArgs)
-
UpdateUI(e.Result)
-
UpdateUI(String.Format("Completed! {0} ", e.Result))
-
CType(sender, System.ComponentModel.BackgroundWorker).Dispose()
-
waitingBackgroundWorker = Nothing
-
End Sub
-
Sub UpdateUI(ByVal msg As String)
-
Dim uiHandler As New ErrorCreateSource(AddressOf UpdateUIIndicatorsMsg)
-
Me.Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Normal, uiHandler, msg)
-
End Sub
-
Sub UpdateUIIndicatorsMsg(ByVal msg As String)
-
StatusMessage.Text = msg
-
End Sub
-
End Class
I think the code is self explanatory, but if you have questions please ask!
-Frinny
Many thanks for the extensive reply Frinny.
I'll try to work through it and see if I can follow it all. It seems one major difference is the fact that the valueSelected is declared differently and not just using the numericUpDown value.
I'll see how I get on and let you know. Thanks again.
Some very useful pointers in your reply Frinny.
I've had a go with my code and it seems the suggestion to have the numericUpDown value stored in a separate variable works just fine.
I'm still fairly new to VB so things like this don't necessarily occur to me but seem fairly obvious when pointed out!
In this instance the Worker reporting back to the UI seems ok without additional code but I'll certainly check back to your post if get into difficulties elsewhere.
Many thanks again.
Sign in to post your reply or Sign up for a free account.
Similar topics
by: lehmann |
last post by:
Hello,
Is it possible to have a disabled input in a form whose value could be
sent when the form is submitted.
I just need the user not to be able to change the input value, but
this value is...
|
by: Dwizz |
last post by:
Hello,
I really hope that someone can help me resolve my problem, I've been
working on it for the past few days, to no avail.
I have an asp:label which gets its value from the database, but what...
|
by: Jeff |
last post by:
I created a form page with HTTP Authentication that works with a MySQL
backend. In addition to a username and
password, there is a 3rd field tied to each entry. For example:
username: 1111...
|
by: whojustdenyme |
last post by:
Hey guys, I'm new to C and programming..so I need some help.
I need a way to round an INPUT number to an INPUT value
so for ex:
enter a decimal: 3.1459
enter the number to round: 3
Answer:...
|
by: vinkumar |
last post by:
Hi,
I have to search for string and replace with user input value using js. I have used inner HTML (objExplorer.Document.body.innerHTML) to get user input.
(Eg: If user inputs web port no. as...
|
by: Chris Riesbeck |
last post by:
I assume the answer to this is "no" with no workarounds, but just checking.
I have a page I open locally from my filesystem for "scrubbing"
Microsoft Word generated junk from HTML. In Firefox 2,...
|
by: gsuns82 |
last post by:
Hi all,
Is it possible to read the input value given by the user by ctrl+v,how do we use java script to read the input?
example: If the user selects a value using ctrl+c from some where...
|
by: manuitpro |
last post by:
Hi All,
I have page with many tabs, in one of the tab i have a form (only a input box) and i want to show some output on the same tab view based on the user input. (bvy using php function)
I...
|
by: jerald m |
last post by:
Hi,
how can i pass the user input value of ( in text box field) to the another Jsp in url?
Form Code
<td>
<input type="text" name="dil_ProjectCode" id="dil_ProjectCode">
</td>
|
by: Ram Horn |
last post by:
Hi,
Is it possible on a single page to make a "text input" value equal to multiple variables, then the variable will be the value of the a hidden input. For example...
This is the start text...
|
by: ryjfgjl |
last post by:
ExcelToDatabase: batch import excel into database automatically...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM).
In this month's session, we are pleased to welcome back...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM).
In this month's session, we are pleased to welcome back...
|
by: Vimpel783 |
last post by:
Hello!
Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
|
by: jfyes |
last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
|
by: PapaRatzi |
last post by:
Hello,
I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
|
by: CloudSolutions |
last post by:
Introduction:
For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
|
by: af34tf |
last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
|
by: Faith0G |
last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
| |