473,386 Members | 1,721 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

RunWorkerAsync using UI input value

116 64KB
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?

Expand|Select|Wrap|Line Numbers
  1. BackgroundWorker1.RunWorkerAsync(myInterval.value)
  2.  
  3. Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
  4. Dim checkcount As Integer = 0
  5. Do checkcount += 1
  6. BackgroundWorker1.ReportProgress(checkcount)
  7. Threading.Thread.Sleep(e.Argument * 1000)
  8. If BackgroundWorker1.CancellationPending = True Then Exit Do
  9. Loop
  10. End Sub
  11.  
Thanks
Nov 26 '14 #1

✓ answered by Frinavale

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:
Expand|Select|Wrap|Line Numbers
  1. <Window x:Class="MainWindow"
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.         Title="MainWindow" Height="350" Width="525"
  5.         xmlns:local="clr-namespace:PracticeProject">
  6.     <Grid>
  7.         <Grid.RowDefinitions>
  8.             <RowDefinition Height="Auto"/>
  9.             <RowDefinition Height="Auto" />
  10.         </Grid.RowDefinitions>
  11.         <TextBlock x:Name="StatusMessage" Text="" Grid.Row="0" />
  12.         <ComboBox x:Name="MyInterval" Grid.Row="1" 
  13.                           SelectedIndex="0"
  14.                           SelectionChanged="MyInterval_SelectionChanged">
  15.             <ComboBox.Items>
  16.                 <ComboBoxItem>0</ComboBoxItem>
  17.                 <ComboBoxItem>5</ComboBoxItem>
  18.                 <ComboBoxItem>8</ComboBoxItem>
  19.                 <ComboBoxItem>10</ComboBoxItem>
  20.             </ComboBox.Items>
  21.         </ComboBox>
  22.     </Grid>
  23. </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:
Expand|Select|Wrap|Line Numbers
  1. Class MainWindow
  2.     Private Delegate Sub ErrorCreateSource(ByVal msg As String)
  3.     Private waitingBackgroundWorker As System.ComponentModel.BackgroundWorker = Nothing ' used to do the work
  4.     Private valueSelected As Integer ' indicates the sleep interval value selected
  5.  
  6.     Private Sub MyInterval_SelectionChanged(sender As System.Object, e As System.Windows.Controls.SelectionChangedEventArgs)
  7.         'Here I would have to use a SyncLock if I wasn't using an Integer type 
  8.         'to pass information to the background worker process in order to prevent multiple things 
  9.         'from setting the value in the middle of processing
  10.  
  11.         'Attempting to parse the item selected into the valueSelected variable (if I can't I stop the process)
  12.         'And checking to make sure the value is greater than 0 (my stop case is when I select 0)
  13.         If Integer.TryParse(DirectCast(DirectCast(sender, ComboBox).SelectedItem, ComboBoxItem).Content, valueSelected) AndAlso valueSelected > 0 Then
  14.  
  15.             If waitingBackgroundWorker Is Nothing Then
  16.                 ' we do not have a background worker yet: creating one and starting it
  17.                 waitingBackgroundWorker = New System.ComponentModel.BackgroundWorker
  18.                 waitingBackgroundWorker.WorkerReportsProgress = True
  19.                 waitingBackgroundWorker.WorkerSupportsCancellation = True
  20.                 AddHandler waitingBackgroundWorker.DoWork, AddressOf WaitBackgroundWorker_DoWork 'the method that is used to do the work
  21.                 AddHandler waitingBackgroundWorker.RunWorkerCompleted, AddressOf WaitBackgroundWorker_RunWorkerCompleted ' the method that is used when work is completed
  22.                 waitingBackgroundWorker.RunWorkerAsync() 'staring the process
  23.             End If
  24.         Else
  25.             'Either the values selected was not a number or the value selected was 0 
  26.             If waitingBackgroundWorker IsNot Nothing Then
  27.                 waitingBackgroundWorker.CancelAsync()
  28.             End If
  29.         End If
  30.     End Sub
  31.     Private Sub WaitBackgroundWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
  32.         Dim checkcount As Integer = 0
  33.         Dim oldTimer = valueSelected
  34.         Do
  35.             checkcount += 1
  36.             sender.ReportProgress(checkcount)
  37.             System.Threading.Thread.Sleep(valueSelected * 1000)
  38.             If sender.CancellationPending = True Then Exit Do
  39.             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))
  40.         Loop
  41.         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)
  42.     End Sub
  43.     Private Sub WaitBackgroundWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As ComponentModel.RunWorkerCompletedEventArgs)
  44.         UpdateUI(e.Result)
  45.         UpdateUI(String.Format("Completed! {0} ", e.Result))
  46.         CType(sender, System.ComponentModel.BackgroundWorker).Dispose()
  47.         waitingBackgroundWorker = Nothing
  48.     End Sub
  49.     Sub UpdateUI(ByVal msg As String)
  50.         Dim uiHandler As New ErrorCreateSource(AddressOf UpdateUIIndicatorsMsg)
  51.         Me.Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Normal, uiHandler, msg)
  52.     End Sub
  53.     Sub UpdateUIIndicatorsMsg(ByVal msg As String)
  54.         StatusMessage.Text = msg
  55.     End Sub
  56. End Class
I think the code is self explanatory, but if you have questions please ask!

-Frinny

3 1297
Frinavale
9,735 Expert Mod 8TB
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:
Expand|Select|Wrap|Line Numbers
  1. <Window x:Class="MainWindow"
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.         Title="MainWindow" Height="350" Width="525"
  5.         xmlns:local="clr-namespace:PracticeProject">
  6.     <Grid>
  7.         <Grid.RowDefinitions>
  8.             <RowDefinition Height="Auto"/>
  9.             <RowDefinition Height="Auto" />
  10.         </Grid.RowDefinitions>
  11.         <TextBlock x:Name="StatusMessage" Text="" Grid.Row="0" />
  12.         <ComboBox x:Name="MyInterval" Grid.Row="1" 
  13.                           SelectedIndex="0"
  14.                           SelectionChanged="MyInterval_SelectionChanged">
  15.             <ComboBox.Items>
  16.                 <ComboBoxItem>0</ComboBoxItem>
  17.                 <ComboBoxItem>5</ComboBoxItem>
  18.                 <ComboBoxItem>8</ComboBoxItem>
  19.                 <ComboBoxItem>10</ComboBoxItem>
  20.             </ComboBox.Items>
  21.         </ComboBox>
  22.     </Grid>
  23. </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:
Expand|Select|Wrap|Line Numbers
  1. Class MainWindow
  2.     Private Delegate Sub ErrorCreateSource(ByVal msg As String)
  3.     Private waitingBackgroundWorker As System.ComponentModel.BackgroundWorker = Nothing ' used to do the work
  4.     Private valueSelected As Integer ' indicates the sleep interval value selected
  5.  
  6.     Private Sub MyInterval_SelectionChanged(sender As System.Object, e As System.Windows.Controls.SelectionChangedEventArgs)
  7.         'Here I would have to use a SyncLock if I wasn't using an Integer type 
  8.         'to pass information to the background worker process in order to prevent multiple things 
  9.         'from setting the value in the middle of processing
  10.  
  11.         'Attempting to parse the item selected into the valueSelected variable (if I can't I stop the process)
  12.         'And checking to make sure the value is greater than 0 (my stop case is when I select 0)
  13.         If Integer.TryParse(DirectCast(DirectCast(sender, ComboBox).SelectedItem, ComboBoxItem).Content, valueSelected) AndAlso valueSelected > 0 Then
  14.  
  15.             If waitingBackgroundWorker Is Nothing Then
  16.                 ' we do not have a background worker yet: creating one and starting it
  17.                 waitingBackgroundWorker = New System.ComponentModel.BackgroundWorker
  18.                 waitingBackgroundWorker.WorkerReportsProgress = True
  19.                 waitingBackgroundWorker.WorkerSupportsCancellation = True
  20.                 AddHandler waitingBackgroundWorker.DoWork, AddressOf WaitBackgroundWorker_DoWork 'the method that is used to do the work
  21.                 AddHandler waitingBackgroundWorker.RunWorkerCompleted, AddressOf WaitBackgroundWorker_RunWorkerCompleted ' the method that is used when work is completed
  22.                 waitingBackgroundWorker.RunWorkerAsync() 'staring the process
  23.             End If
  24.         Else
  25.             'Either the values selected was not a number or the value selected was 0 
  26.             If waitingBackgroundWorker IsNot Nothing Then
  27.                 waitingBackgroundWorker.CancelAsync()
  28.             End If
  29.         End If
  30.     End Sub
  31.     Private Sub WaitBackgroundWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
  32.         Dim checkcount As Integer = 0
  33.         Dim oldTimer = valueSelected
  34.         Do
  35.             checkcount += 1
  36.             sender.ReportProgress(checkcount)
  37.             System.Threading.Thread.Sleep(valueSelected * 1000)
  38.             If sender.CancellationPending = True Then Exit Do
  39.             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))
  40.         Loop
  41.         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)
  42.     End Sub
  43.     Private Sub WaitBackgroundWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As ComponentModel.RunWorkerCompletedEventArgs)
  44.         UpdateUI(e.Result)
  45.         UpdateUI(String.Format("Completed! {0} ", e.Result))
  46.         CType(sender, System.ComponentModel.BackgroundWorker).Dispose()
  47.         waitingBackgroundWorker = Nothing
  48.     End Sub
  49.     Sub UpdateUI(ByVal msg As String)
  50.         Dim uiHandler As New ErrorCreateSource(AddressOf UpdateUIIndicatorsMsg)
  51.         Me.Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Normal, uiHandler, msg)
  52.     End Sub
  53.     Sub UpdateUIIndicatorsMsg(ByVal msg As String)
  54.         StatusMessage.Text = msg
  55.     End Sub
  56. End Class
I think the code is self explanatory, but if you have questions please ask!

-Frinny
Nov 26 '14 #2
robertybob
116 64KB
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.
Nov 27 '14 #3
robertybob
116 64KB
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.
Nov 27 '14 #4

Sign in to post your reply or Sign up for a free account.

Similar topics

2
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...
10
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...
2
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...
2
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:...
2
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...
2
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,...
6
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...
3
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...
2
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>
1
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...
0
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,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
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$) { } ...
0
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...
0
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
0
BarryA
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...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
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...
0
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...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.