views:

369

answers:

3

Hi there, a bit of a juvenile question...

I realise that in a Winforms app, long running code should be executed in its own thread. How does one accomplish this on say, a button click event?

I want to do this in an effort to free up the UI thread so that I can simultaneously overlay the current form with a semi-transparent modal dialog form. I've aleady created the modal dialog form with a neat loading GIF located in the centre that works perfectly on a button click event on its own.

The reason I've chosen this method, is because (1) I want to block any user interaction with the form while the code is being executed, and (2) provide the user with an indication that processing is underway (I dont know how to judge how long a particular piece of code will take to execute, hence opting for an indefinite loading indicator gif).

Also, on the topic of executing code in separate threads...should this not apply to any code, or only specifically to long-running code?

I would really appreciate any help on this matter! thank you!

+6  A: 

One of the simplest ways is to use a BackgroundWorker component. Add a BackgroundWorker to your form, add an event handler for the DoWork event, and call the long-running function from there. You can start it in your button click event handler by calling the RunWorkerAsync method on the BackgroundWorker component.

In order to know when the operation is ready, set up a handler for the RunWorkerCompleted event.

private void Button_Click(object sender, EventArgs e)
{
    myBackgroundWorker.RunWorkerAsync();
}

private void myBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    // long-running operation here; will execute on separate thread
}

private void myBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // operation is ready
}
Fredrik Mörk
Thanks Fredrik. I suppose if you had 2 long-running operations that could be invoked from one of 2 buttons (click), then you would have to add 2 BackgroundWorker components to your form...yes?
Shalan
@Shalan: that would be the easiest approach, yes.
Fredrik Mörk
Thank you, Fredrik
Shalan
+3  A: 

I'll answer the second half of your question (as Fredrik has already explained the BackgroundWorker):

No, it does not make sense to move a task to a separate thread unless the task is long running.

Running a task on a separate thread always incurrs extra overheads. It might take more of the UI thread's time to kick off the thread and handle the task completion then it would have to simply do the task in the first place.

Like any programming technique, you have to weigh up the costs and benifits for the particular situation.

Andrew Shepherd
Thank you, Andrew. That is really solid advice...I'll be sure to remember that!
Shalan
+2  A: 

I will attempt to answer the second part of your question, based on my own experience. You will generally only use threads in one of three circumstances:

  • On operations which will block for noticeable periods of time on system calls (File/Socket IO, etc.)

  • On long running operations where a loss of UI responsiveness is undesirable.

  • With multiple long running operations, where exploiting a multi-core environment is desirable.

As Andrew Shepherd says, there are overheads for using Threads. Threads complicate things dramatically. Never thread for the sake of threading.

Nick
Thank you also to you, Nick. Both yours and Andrew's advice is really insightful, and makes me re-evaluate how I structure my code. Although, what is construed as long-running? Is there a benchmark of sorts to judge this. I mean, I could be developing on an absolute donkey of a machine, compared to a user of the same application that could have a lightning-fast PC. Advice??
Shalan
@Shalan: I would usually define long-running in terms of computational complexity. I'd say there's a good case for using threads whenever you have multiple calculations which can be calculated in parallel, provided each will run reasonably sized data sets in polynomial time (or slower). The other case is with I/O operations (particularly socket I/O), to which I suggest that anything which can be logically deferred and run asynchronously, should be.Don't work too hard to find a use for threads - Ideal candidates for threading will often become clear when designing your software.
Nick
thanks for your input, Nick!
Shalan