5

Do you have a good solution for keeping a 'Please wait' winform 'painted' while an application is performing a long running task ?

I've tried using form.refresh() on each step, but there are a few long running queries that take place, which means that this isn't frequent enough.

Basically this SO Question but, on C# in Excel through VSTO (rather than Python).

Community
  • 1
  • 1
Nick Haslam
  • 1,512
  • 1
  • 24
  • 47
  • Is this really web-forms, or is this winforms? You are talking about Excel and VSTO. and if it is webforms, you don't have a refresh method. – Mitchel Sellers Jan 19 '10 at 15:05
  • Sorry, yes, Winforms, not Webforms.. Have edited the question... It's been a long day... – Nick Haslam Jan 19 '10 at 15:08
  • Any final solution with full source code sample? What about using long running process with steps using C#, SignalR? – Kiquenet Apr 15 '13 at 10:13

4 Answers4

3

As statichippo mentioned, I would use the BackgroundWorker Class. Its purpose is to simplify multi-threading and allow for a worker thread to do the time consuming processing without locking the GUI.

Here is a quote from MSDN:

The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.

Here is a good tutorial how to use the BackgroundWorker class in windows forms: Implementing multi-threading in WinForms using the BackgroundWorker class

There are more complicated ways to implement Multi-Threading in C# for complex scenarios but for most simple scenarios the BackgroundWorker works great (for me at least).

Here are some links I pulled from Google on C# Multi Threading:
MSDN Threading
Introduction to Multithreading in C#

Kiquenet
  • 14,494
  • 35
  • 148
  • 243
orandov
  • 3,256
  • 3
  • 32
  • 32
1

Another option is to use an asynchronous delegate to show the form on a threadpool thread.

Threads in the threadpool are recommended for shorter lived threads that do not last for the entire application duration. As this is to display a short-lived please wait window, the threadpool is a reasonable choice.

The Action delegate (.NET 2.0+) is used along with it's BeginInvoke() method to automatically run the delegate code on a threadpool thread.

Some notes:

  • It is important to use Control.BeginInvoke for any cross thread GUI calls, such as closing the please wait form in ClosePleaseWait().
  • Also, the m_pleaseWaitForm.ShowDialog(); actually starts a new message loop in the new thread. This is what keeps the please wait form alive.
  • Because a threadpool thread is used, this thread is automatically a background thread and will be terminated if the main application is closed.
  • Apart from running on another thread, there is nothing special about Form2. You can place any child controls such as Pictureboxes, labels etc on it.
  • (MethodInvoker)delegate { ... } is just a .NET 2.0 way of running code in a delegate inline.

The example below can be added to a WinForms project containing Form1: the main form, and Form2: the please wait form.

   private Form2 m_pleaseWaitForm = null;

    private void Form1_Shown(object sender, EventArgs e)
    {
        // This code could also be placed in eg. a button click event handler.

        Action<Rectangle> a = new Action<Rectangle>(ShowPleaseWait);

        a.BeginInvoke(this.Bounds, null, null);

        // Do your long running tasks

        ClosePleaseWait();
    }


    private void ShowPleaseWait(Rectangle  bounds)
    {
        // This method runs on the new thread.

        m_pleaseWaitForm = new Form2();

        m_pleaseWaitForm.TopMost = true;
        m_pleaseWaitForm.Location = new Point(bounds.Left + bounds.Width / 2 - m_pleaseWaitForm.Width / 2, bounds.Top + bounds.Height / 2 - m_pleaseWaitForm.Height / 2);

        m_pleaseWaitForm.ShowDialog();

    }

    private void ClosePleaseWait()
    {
        m_pleaseWaitForm.BeginInvoke((MethodInvoker)delegate { m_pleaseWaitForm.Close(); });
    }
Ash
  • 60,973
  • 31
  • 151
  • 169
0

Use a BackgroundWorker

hackerhasid
  • 11,699
  • 10
  • 42
  • 60
  • Man I'm tired -- I thought this was winforms. The answer should be to use AJAX (MS AJAX will work fine). You can use a Timer control to check the status. Then you can redirect on completion. – hackerhasid Jan 19 '10 at 15:05
  • Sorry for the downvote, question was changed from webforms=>winforms. – Jan Jongboom Jan 19 '10 at 15:16
  • I believe statichippo is correct. Using a backgroundworker thread should do this for you. – brunch Jan 19 '10 at 15:19
0

Here's a good example with code in C#.

It is for splash screens specifically, however it is almost identical process (perhaps minus some of the flashy Opacity) to create a Please wait window.

The key information is that you will need a separate thread. This can complicate things however the article gives a good coverage/example of how to do it correctly.

Ash
  • 60,973
  • 31
  • 151
  • 169