By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,319 Members | 1,963 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,319 IT Pros & Developers. It's quick & easy.

Load secondary form in backgroundworker thread

P: n/a
I'm completely new to using background threading, though I have
downloaded and run through several samples and understood how they
worked.

My question is:

I have an app whose primary form will almost always lead to the user
opening a certain child window that's fairly resource intensive to
load. Is it possible to load this form in a backgroundworker and then
use the Show method and hide method as necessary? Anyone know of
simple sample code showing this? I understand that the windows class
is single threaded, so there are probably issues I'm not understanding
yet.

Once you use a backgroundworker to do something with a class or object
in general, are you forever bound to dealing with this object through
the backgroundworker, or can control be handed to the bw to do
something and then when the bw says it's done, you can use the direct
reference again?

Pseudo code in form1:

form2 f = new form2();

use bw to load f

(bw says f it's done loading f)

in other form1 procedures:

if (f.loaded) f.show.....

Thanks, Bob

Jun 26 '07 #1
Share this Question
Share on Google+
9 Replies


P: n/a
On Mon, 25 Jun 2007 17:15:43 -0700, RvGrah
<rv****************@sbcglobal.netwrote:
I have an app whose primary form will almost always lead to the user
opening a certain child window that's fairly resource intensive to
load. Is it possible to load this form in a backgroundworker and then
use the Show method and hide method as necessary?
IMHO, the correct design is to use a BackgroundWorker instance to run the
code that initializes the data for the form, and then when that
initialization is done, create the form on the main thread. Note that
this means you won't be doing the "fairly resource intensive" work from
within the form class. Instead, you need to do it somewhere else in a way
that can then be passed to the form when it's shown.

You could do other designs. For example, have the form itself do the
manipulation of the BackgroundWorker to get the initialization to happen
when the form is shown. But this would require overriding the Show()
method so that it starts the initialization if necessary rather than
actually showing the form, and makes for a somewhat confusing design
IMHO. Putting the initialization code outside of the form makes clear how
to deal with issues like "what happens if I try to close the form before
its initialization has finished?" for example.
Anyone know of
simple sample code showing this? I understand that the windows class
is single threaded, so there are probably issues I'm not understanding
yet.
Important things to know:

* A window is owned by the thread on which it was created. A message
queue exists for that thread, and messages for that window are put in that
queue.

* Even a Form class instance isn't "single-threaded" per se. In spite
of the fact that you need to make sure that window message-based
interactions with the window happen on the owning thread, other
interactions with the class instance can happen on any thread as long as
you make sure that access to data within the class is synchronized.
Once you use a backgroundworker to do something with a class or object
in general, are you forever bound to dealing with this object through
the backgroundworker, or can control be handed to the bw to do
something and then when the bw says it's done, you can use the direct
reference again?
Aside from occasional issues like the message queue I mentioned above,
data instances are completely independent of threads. Any thread can
operate on any data. The tricky part is that any thread can operate on
any data. :) This means that if you have data that is visible by more
than one thread, you need to include code to synchronize access to the
data, to ensure that only one thread is manipulating a specific piece of
data at a time.

A very simple synchronization method would be to use the Control.Invoke()
method (since Form inherits Control, every form has this Invoke()
method). The Control.Invoke() method takes a delegate and executes it on
the same thread that owns the Control instance. This means that if you
use Invoke() from any other thread to manipulate data used by the rest of
your program, you can be assured that the access to that data is done only
on the main thread and will be synchronized with any other access to that
data that is also done on the main thread.

Other synchronization mechanisms include using the "lock" statement, the
Monitor class, a WaitHandle, a Mutex, etc. It happens that there are a
lot of different synchronization methods, each suited to particular kinds
of inter-thread communications.

In your case, since you are already using BackgroundWorker, and because
the RunWorkerCompleted event gets executed on the main thread, it is
essentially doing an implicit Invoke() for you. I think this is the
simplest solution in your case.

Looking at your example pseudo-code:
Pseudo code in form1:

form2 f = new form2();
Instead of this, start the BackgroundWorker doing the initialization.
use bw to load f

(bw says f it's done loading f)
See above. You don't "load" a Form instance, so much as you simply create
it. That instance may in turn load things, but the instance itself is
created as soon as you're done executing the constructor.

So, don't use the BackgroundWorker "to load f". Use it to initialize
whatever data will be needed when you show your form.
in other form1 procedures:

if (f.loaded) f.show.....
Add a handler to the BackgroundWorker.RunWorkerCompleted event, in which
you actually create and show the form, using the data initialized by your
BackgroundWorker.

As a rough example:

void buttonChildForm_Click(object sender, EventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();

bw.DoWork += InitChildFormData;
bw.RunWorkerCompleted += DoneChildFormInit;

bw.RunWorkerAsync();
}

void InitChildFormData(object sender, DoWorkEventArgs e)
{
// do whatever you need to initialize the data. Store the result
in
// e.Result
}

void DoneChildFormInit(object sender, RunWorkerCompletedEventArgs e)
{
Form2 form2 = new Form2(e.Result);

form2.Show();
}

Of course, you will need to cast e.Result back to whatever is the
appropriate type to construct Form2. I didn't bother writing the cast
because I'd have to pick some bogus type name and I figured that would
complicate the example more than just having no casting at all. :)

Pete
Jun 26 '07 #2

P: n/a
Thanks Peter,

I haven't had time to digest this yet but I can see you know a bit
about it. At first glance I think I'll most likely go with the route
of using the backgroundworker to do the database load. The part I'm
still working on (in my head) is the fact that I want the user to not
be aware of any of this going on in the background unless he's
watching a CPU meter or his hard drive led.

Bob Graham

On Jun 25, 6:33 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
On Mon, 25 Jun 2007 17:15:43 -0700, RvGrah

<rvgrahamsevaten...@sbcglobal.netwrote:
I have an app whose primary form will almost always lead to the user
opening a certain child window that's fairly resource intensive to
load. Is it possible to load this form in a backgroundworker and then
use the Show method and hide method as necessary?

IMHO, the correct design is to use a BackgroundWorker instance to run the
code that initializes the data for the form, and then when that
initialization is done, create the form on the main thread. Note that
this means you won't be doing the "fairly resource intensive" work from
within the form class. Instead, you need to do it somewhere else in a way
that can then be passed to the form when it's shown.

You could do other designs. For example, have the form itself do the
manipulation of the BackgroundWorker to get the initialization to happen
when the form is shown. But this would require overriding the Show()
method so that it starts the initialization if necessary rather than
actually showing the form, and makes for a somewhat confusing design
IMHO. Putting the initialization code outside of the form makes clear how
to deal with issues like "what happens if I try to close the form before
its initialization has finished?" for example.
Anyone know of
simple sample code showing this? I understand that the windows class
is single threaded, so there are probably issues I'm not understanding
yet.

Important things to know:

* A window is owned by the thread on which it was created. A message
queue exists for that thread, and messages for that window are put in that
queue.

* Even a Form class instance isn't "single-threaded" per se. In spite
of the fact that you need to make sure that window message-based
interactions with the window happen on the owning thread, other
interactions with the class instance can happen on any thread as long as
you make sure that access to data within the class is synchronized.
Once you use a backgroundworker to do something with a class or object
in general, are you forever bound to dealing with this object through
the backgroundworker, or can control be handed to the bw to do
something and then when the bw says it's done, you can use the direct
reference again?

Aside from occasional issues like the message queue I mentioned above,
data instances are completely independent of threads. Any thread can
operate on any data. The tricky part is that any thread can operate on
any data. :) This means that if you have data that is visible by more
than one thread, you need to include code to synchronize access to the
data, to ensure that only one thread is manipulating a specific piece of
data at a time.

A very simple synchronization method would be to use the Control.Invoke()
method (since Form inherits Control, every form has this Invoke()
method). The Control.Invoke() method takes a delegate and executes it on
the same thread that owns the Control instance. This means that if you
use Invoke() from any other thread to manipulate data used by the rest of
your program, you can be assured that the access to that data is done only
on the main thread and will be synchronized with any other access to that
data that is also done on the main thread.

Other synchronization mechanisms include using the "lock" statement, the
Monitor class, a WaitHandle, a Mutex, etc. It happens that there are a
lot of different synchronization methods, each suited to particular kinds
of inter-thread communications.

In your case, since you are already using BackgroundWorker, and because
the RunWorkerCompleted event gets executed on the main thread, it is
essentially doing an implicit Invoke() for you. I think this is the
simplest solution in your case.

Looking at your example pseudo-code:
Pseudo code in form1:
form2 f = new form2();

Instead of this, start the BackgroundWorker doing the initialization.
use bw to load f
(bw says f it's done loading f)

See above. You don't "load" a Form instance, so much as you simply create
it. That instance may in turn load things, but the instance itself is
created as soon as you're done executing the constructor.

So, don't use the BackgroundWorker "to load f". Use it to initialize
whatever data will be needed when you show your form.
in other form1 procedures:
if (f.loaded) f.show.....

Add a handler to the BackgroundWorker.RunWorkerCompleted event, in which
you actually create and show the form, using the data initialized by your
BackgroundWorker.

As a rough example:

void buttonChildForm_Click(object sender, EventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();

bw.DoWork += InitChildFormData;
bw.RunWorkerCompleted += DoneChildFormInit;

bw.RunWorkerAsync();
}

void InitChildFormData(object sender, DoWorkEventArgs e)
{
// do whatever you need to initialize the data. Store the result
in
// e.Result
}

void DoneChildFormInit(object sender, RunWorkerCompletedEventArgs e)
{
Form2 form2 = new Form2(e.Result);

form2.Show();
}

Of course, you will need to cast e.Result back to whatever is the
appropriate type to construct Form2. I didn't bother writing the cast
because I'd have to pick some bogus type name and I figured that would
complicate the example more than just having no casting at all. :)

Pete

Jun 26 '07 #3

P: n/a
On Tue, 26 Jun 2007 08:18:12 -0700, RvGrah
<rv****************@sbcglobal.netwrote:
I haven't had time to digest this yet but I can see you know a bit
about it. At first glance I think I'll most likely go with the route
of using the backgroundworker to do the database load. The part I'm
still working on (in my head) is the fact that I want the user to not
be aware of any of this going on in the background unless he's
watching a CPU meter or his hard drive led.
Well, what do you mean by "not be aware of any of this"?

You can certainly silently start up the background thread without
providing any feedback to the user. They won't have any idea that
anything's happened until the initialization is done and you show the
form. But are you sure that's really what you want?

Generally speaking, the #1 rule in user interfaces is that when the user
does something, there should be feedback. If they click on a button and
_nothing_ happens, the most likely thing that the user will do is to click
on the button again. Now, you can easily deal with that case, ignoring
the subsequent clicks once you've seen the first one. But that does
nothing to ease the user's frustration.

In most cases, you will want to provide the user with some feedback that
you received their interaction and are doing something about it. You said
originally that you don't want to show the form until the initialization
is done. It's fine if you want to design your UI like that, but you
should put some sort of feedback somewhere else (perhaps in the original
form). With the BackgroundWorker class, you can also subscribe to the
ProgressChanged event, and then in the initialization code call the
ReportProgress() method to cause that event to be raised. In the
ProgressChanged event, you can update the appropriate user feedback to
indicate progress of the initialization.

If you are going to do a lengthy operation in the background, without
providing any feedback to the user at all, you should have a _very_ good
reason for doing so. Consider such a design very carefully, because in
nearly all cases it's wrong. I would even go so far to say that if the
lengthy operation is a direct consequence of an explicit user action, it's
_always_ wrong to not provide feedback.

Pete
Jun 26 '07 #4

P: n/a
What I mean by that is that I want the second form "pre-loaded" in
memory before the user gets around to needing it, so that when he does
click the button to show this second form, it will appear almost
instantly. I don't want him to notice in the sense that I want him to
be able to merrilly work away in form1 without noticing any bogging
down of the machine while the form is pre-loading in the background. I
show a splash screen during the 3-4 seconds it takes to show the first
form, but I don't want to have to show an hourglass for the current 3
seconds or so it takes the second form to be visible if I can get away
from it.

The second form will almost always be called upon sooner or later
while the person has my app open, and system resources are not an
issue, snappy-seeming code speed is an issue.

Thanks, Bob
On Jun 26, 11:46 am, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
On Tue, 26 Jun 2007 08:18:12 -0700, RvGrah

<rvgrahamsevaten...@sbcglobal.netwrote:
I haven't had time to digest this yet but I can see you know a bit
about it. At first glance I think I'll most likely go with the route
of using the backgroundworker to do the database load. The part I'm
still working on (in my head) is the fact that I want the user to not
be aware of any of this going on in the background unless he's
watching a CPU meter or his hard drive led.

Well, what do you mean by "not be aware of any of this"?

You can certainly silently start up the background thread without
providing any feedback to the user. They won't have any idea that
anything's happened until the initialization is done and you show the
form. But are you sure that's really what you want?

Generally speaking, the #1 rule in user interfaces is that when the user
does something, there should be feedback. If they click on a button and
_nothing_ happens, the most likely thing that the user will do is to click
on the button again. Now, you can easily deal with that case, ignoring
the subsequent clicks once you've seen the first one. But that does
nothing to ease the user's frustration.

In most cases, you will want to provide the user with some feedback that
you received their interaction and are doing something about it. You said
originally that you don't want to show the form until the initialization
is done. It's fine if you want to design your UI like that, but you
should put some sort of feedback somewhere else (perhaps in the original
form). With the BackgroundWorker class, you can also subscribe to the
ProgressChanged event, and then in the initialization code call the
ReportProgress() method to cause that event to be raised. In the
ProgressChanged event, you can update the appropriate user feedback to
indicate progress of the initialization.

If you are going to do a lengthy operation in the background, without
providing any feedback to the user at all, you should have a _very_ good
reason for doing so. Consider such a design very carefully, because in
nearly all cases it's wrong. I would even go so far to say that if the
lengthy operation is a direct consequence of an explicit user action, it's
_always_ wrong to not provide feedback.

Pete

Jun 27 '07 #5

P: n/a
As others have said, do the time consuming parts (i.e. db loads) on a worker
thread in the background. When it is done, create form2 and set the
controls, then set a reset event. The form2 open button on form1 will wait
on this event, so if user tries to open form2 before load is done, it will
wait. If reset is set, just Show form.

--
William Stacey [C# MVP]
"RvGrah" <rv****************@sbcglobal.netwrote in message
news:11**********************@m37g2000prh.googlegr oups.com...
| What I mean by that is that I want the second form "pre-loaded" in
| memory before the user gets around to needing it, so that when he does
| click the button to show this second form, it will appear almost
| instantly. I don't want him to notice in the sense that I want him to
| be able to merrilly work away in form1 without noticing any bogging
| down of the machine while the form is pre-loading in the background. I
| show a splash screen during the 3-4 seconds it takes to show the first
| form, but I don't want to have to show an hourglass for the current 3
| seconds or so it takes the second form to be visible if I can get away
| from it.
|
| The second form will almost always be called upon sooner or later
| while the person has my app open, and system resources are not an
| issue, snappy-seeming code speed is an issue.
|
| Thanks, Bob
|
|
| On Jun 26, 11:46 am, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
| wrote:
| On Tue, 26 Jun 2007 08:18:12 -0700, RvGrah
| >
| <rvgrahamsevaten...@sbcglobal.netwrote:
| I haven't had time to digest this yet but I can see you know a bit
| about it. At first glance I think I'll most likely go with the route
| of using the backgroundworker to do the database load. The part I'm
| still working on (in my head) is the fact that I want the user to not
| be aware of any of this going on in the background unless he's
| watching a CPU meter or his hard drive led.
| >
| Well, what do you mean by "not be aware of any of this"?
| >
| You can certainly silently start up the background thread without
| providing any feedback to the user. They won't have any idea that
| anything's happened until the initialization is done and you show the
| form. But are you sure that's really what you want?
| >
| Generally speaking, the #1 rule in user interfaces is that when the user
| does something, there should be feedback. If they click on a button and
| _nothing_ happens, the most likely thing that the user will do is to
click
| on the button again. Now, you can easily deal with that case, ignoring
| the subsequent clicks once you've seen the first one. But that does
| nothing to ease the user's frustration.
| >
| In most cases, you will want to provide the user with some feedback that
| you received their interaction and are doing something about it. You
said
| originally that you don't want to show the form until the initialization
| is done. It's fine if you want to design your UI like that, but you
| should put some sort of feedback somewhere else (perhaps in the original
| form). With the BackgroundWorker class, you can also subscribe to the
| ProgressChanged event, and then in the initialization code call the
| ReportProgress() method to cause that event to be raised. In the
| ProgressChanged event, you can update the appropriate user feedback to
| indicate progress of the initialization.
| >
| If you are going to do a lengthy operation in the background, without
| providing any feedback to the user at all, you should have a _very_ good
| reason for doing so. Consider such a design very carefully, because in
| nearly all cases it's wrong. I would even go so far to say that if the
| lengthy operation is a direct consequence of an explicit user action,
it's
| _always_ wrong to not provide feedback.
| >
| Pete
|
|
Jun 27 '07 #6

P: n/a
William, Thanks for the additional input.

Will this part:
When it is done, create form2 and set the controls, then set a reset event.
Be done on another thread as well? If not, won't it cause some stutter
and bogging on form1 activities?

Thanks

Jun 27 '07 #7

P: n/a
The work (i.e. non-UI work) will be done on another thread. The form
creation and filling the form controls will be queued to the UI thread (i.e.
Invoke/BeginInvoke) after you have all your data. There should not be much
(if any) noticable slowdown on UI unless your filling a thousands of
controls or doing slow work in the Invoke delegates (which you should always
avoid and never make any blocking calls). Thing is, you don't have a lot of
other options. You need to work with all UI elements on the single UI
thread - just the way it is and works pretty well for years.

--
William Stacey [C# MVP]

"RvGrah" <rv****************@sbcglobal.netwrote in message
news:11**********************@m37g2000prh.googlegr oups.com...
| William, Thanks for the additional input.
|
| Will this part:
|
| When it is done, create form2 and set the controls, then set a reset
event.
|
| Be done on another thread as well? If not, won't it cause some stutter
| and bogging on form1 activities?
|
| Thanks
|
Jun 27 '07 #8

P: n/a
On Tue, 26 Jun 2007 21:26:50 -0700, RvGrah
<rv****************@sbcglobal.netwrote:
>When it is done, create form2 and set the controls, then set a reset
event.

Be done on another thread as well? If not, won't it cause some stutter
and bogging on form1 activities?
I'm not sure I understand the question. What are you asking "[will] be
done on another thread as well?" The creation of form2 and initialization
of its controls?

I suppose it's possible you might see a little hiccup, on a particularly
slow computer, if you do the final form creation on the main thread. But
it's doubtful the user would notice, and on any modern computer those
operations are too quick for the user to notice. Conversely, if the
initialization of the form itself is noticeably slow, even after the
underlying data has been initialized, you may want to reconsider the
complexity of the form. You may be (probably are) presenting the user
with far more data than is feasible for them to deal with or than they
need.

Because of all that, I would try to avoid actual creation of the form
until the user asks for it. That operation should be very fast and IMHO
it simplifies the design a bit rather than having to maintain a reference
to the pre-created form.

Now, all that said, depending on how you use the form, it may be feasible
to do the entire creation on a thread other than your main thread. The
big problem there is that it will certainly complicate your design,
because you won't be able to use the BackgroundWorker class. Well, I take
that back: you could use it, but it wouldn't be a good idea because it
would involve you basically taking over a thread pool thread permanently.
That's not a good idea.

The basic issue here is that, as I mentioned at the outset of this thread,
the form needs to be handled by the thread that created it. So if you
create your form on a thread other than the main thread, then all of the
message processing for the form has to happen on that other thread. That
means a) that the thread needs to be around as long as the form is, and b)
when you show the form, you have to run a message pump on that thread to
handle the form. The latter is easily done if you are using
Form.ShowDialog() to show the form, and not too hard even if you're not,
but you'll want to create a thread explicitly using the Thread class to
avoid tying up a thread pool thread while accomplishing the former.

None of this is really all that hard, but it does complicate your life.
You need to consider just how important it is to you that the user not be
delayed by a few seconds, or by the presumably shorter period that would
be required to initialize the actual form controls with whatever data it
is that takes most of the three seconds you mentioned to initialize.

Pete
Jun 27 '07 #9

P: n/a
Now that I think about it, forget the event (it could block the ui thread -
bad). Just Enable the form2 button when it is ready as the last line in
your form2 fill method.

--
William Stacey [C# MVP]

"William Stacey [C# MVP]" <wi************@gmail.comwrote in message
news:Oe**************@TK2MSFTNGP06.phx.gbl...
| As others have said, do the time consuming parts (i.e. db loads) on a
worker
| thread in the background. When it is done, create form2 and set the
| controls, then set a reset event. The form2 open button on form1 will
wait
| on this event, so if user tries to open form2 before load is done, it will
| wait. If reset is set, just Show form.
|
| --
| William Stacey [C# MVP]
|
|
| "RvGrah" <rv****************@sbcglobal.netwrote in message
| news:11**********************@m37g2000prh.googlegr oups.com...
|| What I mean by that is that I want the second form "pre-loaded" in
|| memory before the user gets around to needing it, so that when he does
|| click the button to show this second form, it will appear almost
|| instantly. I don't want him to notice in the sense that I want him to
|| be able to merrilly work away in form1 without noticing any bogging
|| down of the machine while the form is pre-loading in the background. I
|| show a splash screen during the 3-4 seconds it takes to show the first
|| form, but I don't want to have to show an hourglass for the current 3
|| seconds or so it takes the second form to be visible if I can get away
|| from it.
||
|| The second form will almost always be called upon sooner or later
|| while the person has my app open, and system resources are not an
|| issue, snappy-seeming code speed is an issue.
||
|| Thanks, Bob
||
||
|| On Jun 26, 11:46 am, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
|| wrote:
|| On Tue, 26 Jun 2007 08:18:12 -0700, RvGrah
|| >
|| <rvgrahamsevaten...@sbcglobal.netwrote:
|| I haven't had time to digest this yet but I can see you know a bit
|| about it. At first glance I think I'll most likely go with the route
|| of using the backgroundworker to do the database load. The part I'm
|| still working on (in my head) is the fact that I want the user to not
|| be aware of any of this going on in the background unless he's
|| watching a CPU meter or his hard drive led.
|| >
|| Well, what do you mean by "not be aware of any of this"?
|| >
|| You can certainly silently start up the background thread without
|| providing any feedback to the user. They won't have any idea that
|| anything's happened until the initialization is done and you show the
|| form. But are you sure that's really what you want?
|| >
|| Generally speaking, the #1 rule in user interfaces is that when the
user
|| does something, there should be feedback. If they click on a button
and
|| _nothing_ happens, the most likely thing that the user will do is to
| click
|| on the button again. Now, you can easily deal with that case, ignoring
|| the subsequent clicks once you've seen the first one. But that does
|| nothing to ease the user's frustration.
|| >
|| In most cases, you will want to provide the user with some feedback
that
|| you received their interaction and are doing something about it. You
| said
|| originally that you don't want to show the form until the
initialization
|| is done. It's fine if you want to design your UI like that, but you
|| should put some sort of feedback somewhere else (perhaps in the
original
|| form). With the BackgroundWorker class, you can also subscribe to the
|| ProgressChanged event, and then in the initialization code call the
|| ReportProgress() method to cause that event to be raised. In the
|| ProgressChanged event, you can update the appropriate user feedback to
|| indicate progress of the initialization.
|| >
|| If you are going to do a lengthy operation in the background, without
|| providing any feedback to the user at all, you should have a _very_
good
|| reason for doing so. Consider such a design very carefully, because in
|| nearly all cases it's wrong. I would even go so far to say that if the
|| lengthy operation is a direct consequence of an explicit user action,
| it's
|| _always_ wrong to not provide feedback.
|| >
|| Pete
||
||
|
|
Jun 27 '07 #10

This discussion thread is closed

Replies have been disabled for this discussion.