BackgroundWorker not firing on first click --?

R

Rich P

I run an operation using a BackgroundWorker control. I have a button
that I toggle to stop an operation or restart it. Here is the code to
do that:

private void btn_StartStop(...)
{
if (BackgroundWorker1.IsBusy)
{ //stop the operation
BackgroundWorker1.CancelAsync();
btn_StartStop.Text = "Restart Operation";
}
else
{
//restart operation
... do some stuff
BackgroundWorker1.RunWorkerAsync();
btn_StartStop.Text = "Stop Operation";
}
}


The problem I am having is that when I first stop the operation and then
try to restart it -- the code will step right through

//to turn BackroundWorker1 back on
BackgroundWorker1.RunWorkerAsync();


The code recognizes that

BackgroundWorker1.IsBusy.Equals(false)

and it will change the button text to "Stop Operation" -- which suggests
the operation is running --

BackgroundWorker1.IsBusy.Equals(true)
//but this is actually still false -- it's not busy yet

and the code never invokes BackgroundWorker1_DoWork() on the first
click. If I re-click the StartStop button -- it sees that

BackgroundWorker1.IsBusy.Equals(false)

is still the case and this time it WILL invoke

BackgroundWorker1_DoWork()

Subsequent start/stop's work OK. When you click start - it restarts the
operation on the first clikc.

Does anyone have any idea how I can make the first attempt to restart
the operation fire BackgroundWorker1_DoWork() on the first click?

Rich
 
R

Rich P

I've always gone straight to the 'Thread' object and worked with that,
never
used background threads personally.

I have an example of multi-threading in WPF, my 'background thread' just
being a 'Thread' class

http://www.gotinker.com/2010/03/09/dont-shoot-the-messenger-dont-hang-th
e-ui/
<<

Thanks for your reply. Your sample looks very cool. Will this snipet
run in VS2008? I guess I will find out. I was originally using
delegates myself for this project which I started as a VB.Net proj and
then decided to migrate it to C#. It was suggested that BGworker would
be easier to deal with than "something". But it looks like I will go
back to delegates. Does VS2008 have a Dispatcher?


Rich
 
M

Mike Lovell

Thanks for your reply. Your sample looks very cool. Will this snipet
run in VS2008? I guess I will find out. I was originally using
delegates myself for this project which I started as a VB.Net proj and
then decided to migrate it to C#. It was suggested that BGworker would
be easier to deal with than "something". But it looks like I will go
back to delegates. Does VS2008 have a Dispatcher?

Actually it's more dependent on the version of .NET you're using, rather
than the version of Visual Studio.

Delegates were new to .NET Framework 2.0 I believe (someone correct me if
I'm wrong). The example uses WPF, which is new to .NET Framework 3.0.

As I'm a bleeding edge junkie, I'm using Visual Studio 2010 RC and .NET
Framework 4.0. I couldn't say 100% that it will work with any version under
..NET Framework 3.5 SP1 - That's the oldest I go with (that's what I use for
production code).

It will definitely compile and run without error on Visual Studio 2008 with
..NET Framework 3.5 SP1 set as the framework.
 
R

Rich P

It will definitely compile and run without error on Visual Studio 2008
with ..NET Framework 3.5 SP1 set as the framework.
<<

Cool. I think I will give your method a try. It actually resembles the
method I was using in the VB.net version except that I wasn't using
anonymous delegates (they had names, Steve, Bob :). I really like the
anonymous technique.

So just to recap, I have this while loop,

while (something == true)
{
do stuff
}


then in my UI button(s) I will set "something" = false or something =
true and stop/restart the thread. I am thinking I will put the
thread/delegate starter in its own private void(...){for(...) your
technique...}. I have a master start and also a stop/restart buttons.

Does that sound viable?



Rich
 
M

Mike Lovell

Cool. I think I will give your method a try. It actually resembles the
method I was using in the VB.net version except that I wasn't using
anonymous delegates (they had names, Steve, Bob :). I really like the
anonymous technique.

So just to recap, I have this while loop,

while (something == true)
{
do stuff
}

As long as that's not an infinite loop, yes.

So you'd disable the button used to press it, run your stuff, then enable
the button the other end.

You just need to use the Dispatcher to talk to the UI thread.

BTW, since while checks for true, you don't need the "== true" bit. just

while (something)
{
do stuff
}
then in my UI button(s) I will set "something" = false or something =
true and stop/restart the thread. I am thinking I will put the
thread/delegate starter in its own private void(...){for(...) your
technique...}. I have a master start and also a stop/restart buttons.

Does that sound viable?

It does indeed, load it up, play around with it. Nobody gets it 100%
perfect bug free first run.
 
R

Rich P

You just need to use the Dispatcher to talk to the UI thread.
<<

Well, I entered the sample code into my project, and have a reference to
System.Threading, but VS2008 (.Net 3.51 SP1) is complaining about
Dispatcher. Any suggestions what I could so that Dispatcher will work?

BTW, my while loop will be doing this: I will read 14,000+ imagefile
names to a list and display each image in a picturebox for 1 seccond (or
2 whatever the user selects). Once all 14,000+ images have been
displayed (one at a time) the loop starts over until "something" = false
(well, theoretically - it is a sort of search program). If the user
sees all the images but needs to see them again the loop will continue
indefinitely until the app is either closed down or the stop button is
clicked. Will that be an issue for your method?

Thanks for all the help.

Rich
 
M

Mike Lovell

Well, I entered the sample code into my project, and have a reference to
System.Threading, but VS2008 (.Net 3.51 SP1) is complaining about
Dispatcher. Any suggestions what I could so that Dispatcher will work?

Is it a WPF project? This was a WPF demo. You could download the project,
I'm not sure what's required (backward compatibility wise) to run a VS2010
project in VS2008. Hard to say without seeing it, if you post the project I
could probably tell you the problem pretty quickly. I've probably got a
VS2008 installation around here somewhere (sorry I'm a bleeding edge
junkie!).
BTW, my while loop will be doing this: I will read 14,000+ imagefile
names to a list and display each image in a picturebox for 1 seccond (or
2 whatever the user selects). Once all 14,000+ images have been
displayed (one at a time) the loop starts over until "something" = false
(well, theoretically - it is a sort of search program). If the user
sees all the images but needs to see them again the loop will continue
indefinitely until the app is either closed down or the stop button is
clicked. Will that be an issue for your method?

Well no amount of load will be an issue, but if it's running for a very long
time you might to consider giving the user the option to terminate the
thread. You can just kill the thread although a nicer method might be to
have a Boolean which is set when a termination is required. And your loop
checks this each time it goes around, that way they might have to wait 1-2
second but it will be a nice clean termination. Then once it's terminated
it re-enables your start button (or whatever you're using).

As long as you control your interaction between the worker thread and the UI
thread you'll be fine. It's not hard to communicate between the two based
on just simple shared objects (as I mentioned, a Boolean for storing state
is probably the simplest method). Then just test the various methods and
see which one fits into what you want the end user experience to be.
 
P

Peter Duniho

Rich said:
[...]
Does anyone have any idea how I can make the first attempt to restart
the operation fire BackgroundWorker1_DoWork() on the first click?

The main problem is that you're trying to depend on the current state of
the worker rather than tracking what your code has actually done.

Common correct implementations include:

– keep a flag, set when you start the worker, cleared when it's
finally finished

– use the button Text or Tag field as a flag, for example

– use two different buttons, enabling the "stop" button when you're
starting the worker, and the "start" button when it finally finishes

Note that in all of the above, the key is to change the state that
tracks the worker when you start the worker, rather than waiting for it
to actually get going, and to change it back when the worker has
completed (e.g. in the RunWorkerCompleted event handler).

It may be that Mike's other code example is helpful to you, but
regardless of what threading technique you use, you will need to get
used to use techniques similar to the above.

Pete
 
R

Rich P

Hi Pete,

thanks for the suggestion. Here is my actual code in the start/stop
button. I am not clear on how I manage state with the BackgroundWorker.
And I suspect that Mike's code sample is for a WPF app which mine is a
straightforward winform app (if that's not the case -- how to reference
Dispatcher?). Would I be able to manage BackgroundWorkder state from
this button? How to do this?

private void btnStopStart_Click(object sender, EventArgs e)
{
if (bgWkr.IsBusy) //backgroundworker is running
{
bgWkr.CancelAsync(); // stop BackgroundWorker
bRunsPics = false; //boolean to exit While Loop
btnStopStart.Text = "Viewer Go";
}
else
{
if (txtPicCount.Text != "")
iPicCount = Int32.Parse(txtPicCount.Text);
else
txtPicCount.Text = iPicCount.ToString();

//--here is where not always firing
bgWkr.RunWorkerAsync(iPicCount); // start BackgroundWorker
bRunsPics = true; //boolean for the While Loop
btnStopStart.Text = "Stop Viewer";
}
}



Rich
 
R

Rich P

I figured out the problem: in BackgroundWorker_DoWork I have a While
loop with a boolean to break out of the loop (stop backgroundworker).
On re-start of bacgroundworker_DoWrok I was setting this boolean to true
after I called backgroundworker_DoWork. So the loop was not being
entered until after the 2nd time I clicked on the restart button.
else
{
if (txtPicCount.Text != "")
iPicCount = Int32.Parse(txtPicCount.Text);
else
txtPicCount.Text = iPicCount.ToString();

//--here is where not always firing
bgWkr.RunWorkerAsync(iPicCount); // start BackgroundWorker

//--need to move this line above
//bgWkr.RunWorkerAsync(iPicCount);
bRunsPics = true; //boolean for the While Loop
btnStopStart.Text = "Stop Viewer";
}
<<

else
{
if (txtPicCount.Text != "")
iPicCount = Int32.Parse(txtPicCount.Text);
else
txtPicCount.Text = iPicCount.ToString();


bRunsPics = true; //boolean for the While Loop
//now this call works correctly
bgWkr.RunWorkerAsync(iPicCount); // start BackgroundWorker

btnStopStart.Text = "Stop Viewer";
}
<<

Rich
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top