473,320 Members | 1,950 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,320 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 1295
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: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
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...
1
isladogs
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...
0
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...
0
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...
1
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)...
1
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...
0
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
0
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...

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.