views:

411

answers:

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).

+1  A: 

Use a BackgroundWorker

statichippo
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.
statichippo
MSDN link:http://msdn.microsoft.com/en-us/magazine/cc164051.aspx
statichippo
Sorry for the downvote, question was changed from webforms=>winforms.
Jan Jongboom
I believe statichippo is correct. Using a backgroundworker thread should do this for you.
Ben Runchey
ok, then my original answer should be correct
statichippo
A: 

you can use ajax and wait for the return instead of using full page posts

Casual Jim
+1  A: 

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
Thanks for this link. Works really well, and integrates into my Excel VSTO app really nicely!
Nick Haslam
A: 

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
+2  A: 

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#

I hope this helps.

Oran

orandov