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 1297
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: taylorcarr |
last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
|
by: Charles Arthur |
last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
|
by: aa123db |
last post by:
Variable and constants
Use var or let for variables and const fror constants.
Var foo ='bar';
Let foo ='bar';const baz ='bar';
Functions
function $name$ ($parameters$) {
}
...
|
by: ryjfgjl |
last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
|
by: emmanuelkatto |
last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud.
Please let me know.
Thanks!
Emmanuel
|
by: BarryA |
last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
by: Sonnysonu |
last post by:
This is the data of csv file
1 2 3
1 2 3
1 2 3
1 2 3
2 3
2 3
3
the lengths should be different i have to store the data by column-wise with in the specific length.
suppose the i have to...
|
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
| |