Home All Groups Group Topic Archive Search About

c# newbie needs help with backgroundworker

Author
11 Jun 2009 12:07 PM
c-sharp newbie!
Dear all,

I have a form which temporarily creates another form and has a
progressbar on it. I got trouble with updating the screen, if I didn't
use a background-worker. Therefore: My code looks something like the
following:

    public partial class newForm : Form
    {
        public newForm()
        {
            InitializeComponent();

            //this.Show();
            //this.Activate();
            this.progressBar1.Step = 1;
            this.progressBar1.Maximum = 100;

            BackgroundWorker bw0 = new BackgroundWorker();
            bw0.WorkerReportsProgress = true;

            bw0.DoWork += delegate(object sender0, DoWorkEventArgs e0)
            {
                for (int i = 0; i < 15; i++)
                {
                    System.Threading.Thread.Sleep(50);
                    bw0.ReportProgress(i);
                }
            };
            bw0.ProgressChanged += delegate(object sender0,
ProgressChangedEventArgs e0)
            {
                this.progress_indicator.Text = string.Format("{0}%",
e0.ProgressPercentage);
                this.progressBar1.PerformStep();
            };
            bw0.RunWorkerCompleted += delegate(object sender0,
RunWorkerCompletedEventArgs e0)
            {
                   // Here I insert 6 extra background-workers after
the previous completed - this is wrong!
            }


Okay: My problem is that when I put code inside
bwXXXX.RunWorkerCompleted, everything works - except that I cannot
continue to update by using my bwXXXXX.ReportProgress(i). Therefore I
have some really really ugly code with many layers of background-
workers...

In addition, I need to get something like: (int)this.Handle

I cannot seem to be able to get: (int)this.Handle inside any of my
bwXXXXX.DoWork'ers.... Instead of having all my background-workers, I
only need a single one and put my code inside the bw0.DoWork (my code
is 100% sequential).

Any hints on why this doesn't work - do I need to post more code? I
hope this is sufficient for a qualified answer...

Author
11 Jun 2009 5:17 PM
Peter Duniho
On Thu, 11 Jun 2009 05:07:43 -0700, c-sharp newbie! <newsbo***@gmail.com> 
wrote:

Show quoteHide quote
> [...]
>             bw0.RunWorkerCompleted += delegate(object sender0,
> RunWorkerCompletedEventArgs e0)
>             {
>                    // Here I insert 6 extra background-workers after
> the previous completed - this is wrong!
>             }
>
>
> Okay: My problem is that when I put code inside
> bwXXXX.RunWorkerCompleted, everything works - except that I cannot
> continue to update by using my bwXXXXX.ReportProgress(i). Therefore I
> have some really really ugly code with many layers of background-
> workers...

What does "I cannot continue to update by using my 
byXXXXX.ReportProgress(i)" mean?  Why, when the problem you're having is 
apparently related to the code you put into the RunWorkerCompleted event 
handler, is that the one event handler that you failed to actually show 
the code for?

> In addition, I need to get something like: (int)this.Handle
>
> I cannot seem to be able to get: (int)this.Handle inside any of my
> bwXXXXX.DoWork'ers.... Instead of having all my background-workers, I
> only need a single one and put my code inside the bw0.DoWork (my code
> is 100% sequential).

Suggestion: instead of casting the Handle value, use the ToInt32() method 
on it.

As for the specific concern, there's nothing in the code you posted that 
demonstrates how you're trying to "get: (int) this.Handle", never mind 
what mind be going wrong with such code.  Assuming your DoWork event 
handlers are methods within your Form sub-class, "this.Handle" should be a 
valid expression, and it should evaluate to some specific value at 
run-time.

> Any hints on why this doesn't work - do I need to post more code? I
> hope this is sufficient for a qualified answer...

Unfortunately, it's not.  See above for specific things that are missing 
from the code, and keep in mind that a _complete_ code example is almost 
always the best.  There's no way for anyone to actually compile and run 
the code you posted without extra work, including some guesswork.  In any 
case, if you don't post any of the code that is actually giving you 
problems, it's impossible for anyone to provide any useful comments about 
that code.

Pete
Are all your drivers up to date? click for free checkup

Author
12 Jun 2009 3:01 PM
c++ newbie!
Show quote Hide quote
On 11 Jun., 19:17, "Peter Duniho" <NpOeStPe***@nnowslpianmk.com>
wrote:
> On Thu, 11 Jun 2009 05:07:43 -0700, c-sharp newbie! <newsbo***@gmail.com>  
> wrote:
>
> > [...]
> >             bw0.RunWorkerCompleted += delegate(object sender0,
> > RunWorkerCompletedEventArgs e0)
> >             {
> >                    // Here I insert 6 extra background-workers after
> > the previous completed - this is wrong!
> >             }
>
> > Okay: My problem is that when I put code inside
> > bwXXXX.RunWorkerCompleted, everything works - except that I cannot
> > continue to update by using my bwXXXXX.ReportProgress(i). Therefore I
> > have some really really ugly code with many layers of background-
> > workers...
>
> What does "I cannot continue to update by using my  
> byXXXXX.ReportProgress(i)" mean?

Ok, it means: I cannot continue to update my GUI as I could use in the
bw0.DoWork-function. If I try to update my GUI in the
bw0.RunWorkerCompleted-function, it fails. That's what it means... I
then found the explanation, that there are separate threads.

I need to pass information from the GUI-thread to the worker-thread -
that's my problem. I don't know how to do this.

> Why, when the problem you're having is  
> apparently related to the code you put into the RunWorkerCompleted event  
> handler, is that the one event handler that you failed to actually show  
> the code for?

I'm using an API which I don't think any of you have. The API requires
that I pass (int)this.Handle, to the API-function I want to use.
Therefore I only need how to pass the value of (int) this.Handle (from
the GUI-thread) to the worker thread. At least, that is what I
think...

> > In addition, I need to get something like: (int)this.Handle
>
> > I cannot seem to be able to get: (int)this.Handle inside any of my
> > bwXXXXX.DoWork'ers.... Instead of having all my background-workers, I
> > only need a single one and put my code inside the bw0.DoWork (my code
> > is 100% sequential).
>
> Suggestion: instead of casting the Handle value, use the ToInt32() method  
> on it.

Okay, but still. I guess I don't complety understand the concept of
this.handle... Any help or comments on "this.handle" in relation to
the two threads in background-worker (GUI- vs. worker-thread) would be
appreciated...

> As for the specific concern, there's nothing in the code you posted that  
> demonstrates how you're trying to "get: (int) this.Handle", never mind  
> what mind be going wrong with such code.  Assuming your DoWork event  
> handlers are methods within your Form sub-class, "this.Handle" should be a  
> valid expression, and it should evaluate to some specific value at  
> run-time.

Here's what I try to do:

------------ CODE THAT DOESN'T WORK:------------
            bw0.DoWork += delegate(object sender0, DoWorkEventArgs e0)
            {
                for (int i = 0; i < 5; i++)
                {
                    System.Threading.Thread.Sleep(50);
                    bw0.ReportProgress(i);
                }
                int test = (int)this.Handle; //// DOESN'T WORK: "NOT
IN THE GUI-THREAD"
                MessageBox.Show("integer = " + Convert.ToString
(test));

                for (int i = 5; i < 15; i++)
                {
                    System.Threading.Thread.Sleep(50);
                    bw0.ReportProgress(i);
                }
                // do something more....
            };

------------ CODE THAT WORKS:------------

            bw0.RunWorkerCompleted += delegate(object sender0,
RunWorkerCompletedEventArgs e0)
            {
                int test = (int)this.Handle; //// WORKS BECAUSE WE'RE
IN THE GUI-THREAD
                MessageBox.Show("integer = " + Convert.ToString
(test));

                // however: This doesn't work:
                for (int i = 0; i < 5; i++)
                {
                    System.Threading.Thread.Sleep(50);
                    bw0.ReportProgress(i); // New non-gui "worker-
thread", therefore this fails
                }


> > Any hints on why this doesn't work - do I need to post more code? I
> > hope this is sufficient for a qualified answer...
>
> Unfortunately, it's not.  See above for specific things that are missing  
>  from the code, and keep in mind that a _complete_ code example is almost  
> always the best.  There's no way for anyone to actually compile and run  

I cannot post complete code, because I'm using some API which I guess
you don't have. And my question should be so general, that it suffices
(I hope).

> the code you posted without extra work, including some guesswork.  In any  
> case, if you don't post any of the code that is actually giving you  
> problems, it's impossible for anyone to provide any useful comments about  
> that code.

I think I described my problem, however in a newbie-way and that might
not be good enough. Now I believe I've showed it.
Author
12 Jun 2009 5:30 PM
Peter Duniho
On Fri, 12 Jun 2009 08:01:43 -0700, c++ newbie! <newsbo***@gmail.com> 
wrote:

> [...]
> I need to pass information from the GUI-thread to the worker-thread -
> that's my problem. I don't know how to do this.

The most straightforward way is to use the RunWorkerAsync() overload that 
allows you to pass an argument to your DoWork event handler (the argument 
value can be retrieved from the DoWorkEventArgs object passed to the 
handler).

Alternative methods include:

     -- Copying the value of the Handle property to a private class member 
field, and then reading it from there.  The problem isn't with the value, 
it's with the Handle property itself.

     -- Accessing the property using Control.Invoke() on an anonymous 
method that gets the property value and returns it.  Invoked methods can 
return values to the caller, even when using Control.Invoke().

One thing that still bugs me about your code example is that the "CODE 
THAT DOESN"T WORK" and the "CODE THAT WORKS" looks basically the same.  
The only significant difference is that in one case you are handling the 
DoWork event, and in the other case you are handling the 
RunWorkerCompleted event.  But, those events are for completely different 
purposes.  It doesn't make sense that you could treat the events 
interchangeably.

In particular, while you may be able to resolve the business of retrieving 
the Handle property value in the worker thread, whether you can safely use 
that value anywhere else is still open to question.  Likewise, putting 
code in the RunWorkerCompleted event handler that does the same thing as 
the code in your DoWork event handler begs the question: what's the point 
of the background worker thread at all, if you are satisfied executing the 
exact same code on the main GUI thread?

Anyway, hopefully the information above helps you solve your problem.

Pete
Author
14 Jun 2009 2:05 PM
c++ newbie!
On 12 Jun., 19:30, "Peter Duniho" <NpOeStPe***@nnowslpianmk.com>
wrote:
> On Fri, 12 Jun 2009 08:01:43 -0700, c++ newbie! <newsbo***@gmail.com>  
> wrote:
>
> > [...]
> > I need to pass information from the GUI-thread to the worker-thread -
> > that's my problem. I don't know how to do this.
>
> The most straightforward way is to use the RunWorkerAsync() overload that  
> allows you to pass an argument to your DoWork event handler (the argument  
> value can be retrieved from the DoWorkEventArgs object passed to the  
> handler).

Aah, thank you very much! This seem to work on a minimal example here
at home :-)

However, I have to check it for real on monday/tuesday on my real code
and cross my fingers that everything works out :-)

> Alternative methods include:
>
>      -- Copying the value of the Handle property to a private class member  
> field, and then reading it from there.  The problem isn't with the value,  
> it's with the Handle property itself.

What you're telling me, is a true eye-opener. I value that, however
what do you mean with the last sentence?

I think I understand the alternative method, but not the problem...

>      -- Accessing the property using Control.Invoke() on an anonymous  
> method that gets the property value and returns it.  Invoked methods can  
> return values to the caller, even when using Control.Invoke().

Thanks: Finally, I got something to work and began understanding Invoke
() a bit. This page helped a lot: http://msdn.microsoft.com/en-us/library/ms171728.aspx

I now have something like this:

        delegate int getHandleCallback(); // I haven't really
understood this yet

        private int getHandle()
        {
            return (int)this.Handle;
        }

And in my doworker-method:

            int val;
            getHandleCallback GH = new getHandleCallback(getHandle);

            object valO = this.Invoke(GH);
            val = (int)valO;
            //val = (int)this.Handle; // produces some thread error/
casts exception
            MessageBox.Show("Value is (from this.Invoke): " +
val.ToString());


> One thing that still bugs me about your code example is that the "CODE  
> THAT DOESN"T WORK" and the "CODE THAT WORKS" looks basically the same.

Yes, because I don't want my code in the "worker-completed UI"-thread,
but in the worker-thread and I got exceptions when I tried to move my
code into the worker-thread. So I don't understand exactly, what's
bugging you other than I couldn't make it work before (I haven't
tested it on my whole code, I just ran a minimal example here at home
which I believe has shown that your suggestions really have helped
me)?

> The only significant difference is that in one case you are handling the  
> DoWork event, and in the other case you are handling the  
> RunWorkerCompleted event.  But, those events are for completely different  
> purposes.  It doesn't make sense that you could treat the events  
> interchangeably.

When you're a noob like me, you just put the code whereever it works
out. When you're trying to learn to improve your code like me, I ask
for help because I want all "work-stuff" in the worker-thread instead
of the completed-thread. My real problem is that I have multiple
embedded background-workers in the run-completed method, instead of
putting all inside one single background-worker "do-work"-method.

By following your suggestions I improve my code a lot, make it easier
to look at and doesn't need multiple background-workers due to the
requirement for knowing things from the main (UI)-thread.

I'm not sure if I removed your concerns?

> In particular, while you may be able to resolve the business of retrieving  
> the Handle property value in the worker thread, whether you can safely use  
> that value anywhere else is still open to question.  Likewise, putting  

Yes, I agree: Whether I can use it anywhere else is still a question I
have to check tomorrow... I hope - or else I guess I must learn more
about invoke... I guess by using invoke, is the way to do it properly,
if I get problems...

> code in the RunWorkerCompleted event handler that does the same thing as  
> the code in your DoWork event handler begs the question: what's the point  
> of the background worker thread at all, if you are satisfied executing the  
> exact same code on the main GUI thread?

The point is that if you don't use a BW, the form-window is "locked"
while you're running your code. You don't see any progress indication
and my labels don't get updated, so the user can't see what's
happening. Therefore you need a background-worker. And so far most of
my code was ran in the "completed"-event because that was the only
place I could make it work. This introduced the need for multiple
background-workers, because I have multiple tasks I want to solve
while the user can see the program progress.

> Anyway, hopefully the information above helps you solve your problem.

Yes, it was very helpful and thank you. I still need to check it
tomorrow/tuesday I hope on my full code. My test code here at home
shows me that your suggestions was very valuable and I learned
something from them.
Author
12 Jun 2009 4:11 PM
Patrice
If this is sequential work (my understanding is that you want a single
background thread at any one time ?) , you could put all in DoWork and use a
single Backgroundworker ?

Another option would be to update the DoWork delegate and then use the bsame
backgrounder again...

From the code I see I'm not sure what you are trying to do (dowork currently
just updates the progress, it should be used to perform the actual work (in
additioon to updateing the progress).

Not related but as a side note putting the thread to sleep shouldn' t be
needed. The problme you have here is that if you call the UI thread too
frequently you kill the benefit of using a background thread. My pattern
here is to report progress if progress really changed (but this is unrelated

--
Patrice

"c-sharp newbie!" <newsbo***@gmail.com> a écrit dans le message de groupe de
discussion :
5d4a0546-aeb2-4313-9f1a-f4644af83***@21g2000vbk.googlegroups.com...
Show quoteHide quote
> Dear all,
>
> I have a form which temporarily creates another form and has a
> progressbar on it. I got trouble with updating the screen, if I didn't
> use a background-worker. Therefore: My code looks something like the
> following:
>
>    public partial class newForm : Form
>    {
>        public newForm()
>        {
>            InitializeComponent();
>
>            //this.Show();
>            //this.Activate();
>            this.progressBar1.Step = 1;
>            this.progressBar1.Maximum = 100;
>
>            BackgroundWorker bw0 = new BackgroundWorker();
>            bw0.WorkerReportsProgress = true;
>
>            bw0.DoWork += delegate(object sender0, DoWorkEventArgs e0)
>            {
>                for (int i = 0; i < 15; i++)
>                {
>                    System.Threading.Thread.Sleep(50);
>                    bw0.ReportProgress(i);
>                }
>            };
>            bw0.ProgressChanged += delegate(object sender0,
> ProgressChangedEventArgs e0)
>            {
>                this.progress_indicator.Text = string.Format("{0}%",
> e0.ProgressPercentage);
>                this.progressBar1.PerformStep();
>            };
>            bw0.RunWorkerCompleted += delegate(object sender0,
> RunWorkerCompletedEventArgs e0)
>            {
>                   // Here I insert 6 extra background-workers after
> the previous completed - this is wrong!
>            }
>
>
> Okay: My problem is that when I put code inside
> bwXXXX.RunWorkerCompleted, everything works - except that I cannot
> continue to update by using my bwXXXXX.ReportProgress(i). Therefore I
> have some really really ugly code with many layers of background-
> workers...
>
> In addition, I need to get something like: (int)this.Handle
>
> I cannot seem to be able to get: (int)this.Handle inside any of my
> bwXXXXX.DoWork'ers.... Instead of having all my background-workers, I
> only need a single one and put my code inside the bw0.DoWork (my code
> is 100% sequential).
>
> Any hints on why this doesn't work - do I need to post more code? I
> hope this is sufficient for a qualified answer...

Bookmark and Share