52

I have a form that is very slow because there are many controls placed on the form.

As a result the form takes a long time to loaded.

How do I load the form first, then display it and while loading delay show another form which that have message like "Loading... please wait.?"

Osama Rizwan
  • 615
  • 1
  • 7
  • 19
Sadegh
  • 4,181
  • 9
  • 45
  • 78

12 Answers12

64

Using a separate thread to display a simple please wait message is overkill especially if you don't have much experience with threading.

A much simpler approach is to create a "Please wait" form and display it as a mode-less window just before the slow loading form. Once the main form has finished loading, hide the please wait form.

In this way you are using just the one main UI thread to firstly display the please wait form and then load your main form.

The only limitation to this approach is that your please wait form cannot be animated (such as a animated GIF) because the thread is busy loading your main form.

PleaseWaitForm pleaseWait=new PleaseWaitForm ();

// Display form modelessly
pleaseWait.Show();

//  ALlow main UI thread to properly display please wait form.
Application.DoEvents();

// Show or load the main form.
mainForm.ShowDialog();
Ash
  • 60,973
  • 31
  • 151
  • 169
  • exist way to using animated images in your approach to still animated? – Sadegh Dec 17 '09 at 08:12
  • 1
    @Sadegh, you would need to use a control on your please wait form that internally creates a thread to animate the image. I don't think the standard PictureBox does this. However if you definitely need animation then some of David's linked pages are worth looking at. – Ash Dec 18 '09 at 00:48
  • 7
    Never use `Application.DoEvents();`! – CodeTherapist Oct 26 '12 at 18:38
  • 31
    @C Sharper, your comment must have been truncated and the word 'inappropriately' was lost from the end. – Ash Nov 28 '12 at 01:54
  • Never thought to do it this way, saved me a LOT of time. Works flawlessly. Thanks! – CODe Jan 30 '14 at 00:15
  • This also works for a Work delegate passed to a please wait form... Always forget DoEvents as an option. – tobriand Jan 27 '15 at 18:29
  • 1
    Problem is, main thread doesn't render anything until form load is done. So even if I call another form at the very beginning of main form load, it will still become visible only after main form loads, defeating the whole purpose of a loading screen. – Spero Jul 04 '19 at 16:46
32

I looked at most the solutions posted, but came across a different one that I prefer. It's simple, doesn't use threads, and works for what I want it to.

http://weblogs.asp.net/kennykerr/archive/2004/11/26/where-is-form-s-loaded-event.aspx

I added to the solution in the article and moved the code into a base class that all my forms inherit from. Now I just call one function: ShowWaitForm() during the frm_load() event of any form that needs a wait dialogue box while the form is loading. Here's the code:

public class MyFormBase : System.Windows.Forms.Form
{
    private MyWaitForm _waitForm;

    protected void ShowWaitForm(string message)
    {
        // don't display more than one wait form at a time
        if (_waitForm != null && !_waitForm.IsDisposed) 
        {
            return;
        }

        _waitForm = new MyWaitForm();
        _waitForm.SetMessage(message); // "Loading data. Please wait..."
        _waitForm.TopMost = true;
        _waitForm.StartPosition = FormStartPosition.CenterScreen;
        _waitForm.Show();
        _waitForm.Refresh();

        // force the wait window to display for at least 700ms so it doesn't just flash on the screen
        System.Threading.Thread.Sleep(700);         
        Application.Idle += OnLoaded;
    }

    private void OnLoaded(object sender, EventArgs e)
    {
        Application.Idle -= OnLoaded;
        _waitForm.Close();
    }
}

MyWaitForm is the name of a form you create to look like a wait dialogue. I added a SetMessage() function to customize the text on the wait form.

goku_da_master
  • 4,257
  • 1
  • 41
  • 43
  • it says mywaitform doesnt exist – CDrosos May 30 '17 at 15:47
  • I found this as a Best approach, I designed my own wait form and it' working fine.. – Bharat Dec 24 '17 at 08:24
  • This is an excellent idea to place a static image or text on the screen while waiting for the form to open. I changed the call to ShowWaitForm and placed it in the base class. Then I added a boolean property in the base class so that I could just set the property and it would load the wait form. Awesome solution! – Nathan Apr 02 '19 at 20:45
19

You want to look into 'Splash' Screens.

Display another 'Splash' form and wait until the processing is done.

Here is an example on how to do it.

David Basarab
  • 72,212
  • 42
  • 129
  • 156
12

A simple solution:

using (Form2 f2 = new Form2())
{
    f2.Show();
    f2.Update();

    System.Threading.Thread.Sleep(2500);
} // f2 is closed and disposed here

And then substitute your Loading for the Sleep.
This blocks the UI thread, on purpose.

H H
  • 263,252
  • 30
  • 330
  • 514
  • I like this simple solution. Yes, it doesnt work for animated gifs but I have just slapped an image of an hourglass on the dialog and am good to go. – Ocean Airdrop Jan 13 '21 at 09:39
10

Another way of making "Loading screen" only display at certain time is, put it before the event and dismiss it after event finished doing it's job.

For example: you want to display a loading form for an event of saving result as MS Excel file and dismiss it after finished processing, do as follows:

LoadingWindow loadingWindow = new LoadingWindow();

try
{
    loadingWindow.Show();                
    this.exportToExcelfile();
    loadingWindow.Close();
}
catch (Exception ex)
{
    MessageBox.Show("Exception EXPORT: " + ex.Message);
}

Or you can put loadingWindow.Close() inside finally block.

ahmadnaziF
  • 149
  • 3
  • 8
  • 1
    this will almost never work. The foreground thread continues to exportToExcelFile where it is busy before the loadingWindow will show. – rune711 Nov 26 '16 at 18:06
5

You should create a background thread to to create and populate the form. This will allow your foreground thread to show the loading message.

Chris
  • 26,744
  • 48
  • 193
  • 345
unholysampler
  • 17,141
  • 7
  • 47
  • 64
5

I put some animated gif in a form called FormWait and then I called it as:

// show the form
new Thread(() => new FormWait().ShowDialog()).Start();

// do the heavy stuff here

// get the form reference back and close it
FormWait f = new FormWait();
f = (FormWait)Application.OpenForms["FormWait"];
f.Close();
Daniel Bonetti
  • 2,306
  • 2
  • 24
  • 33
  • 3
    I tried using this, but I get an IO illegal thread crossing exception. I modified it by making it "thread-safe". Not the best practice, but for a simple wait form it's acceptable: Replace f.Close() with f.Invoke(new ThreadStart(delegate {f.Close();})); – Schrodo_Baggins Mar 03 '17 at 15:48
  • I've added a tested solution here: https://stackoverflow.com/questions/15769276/best-way-to-display-a-progress-form-while-a-method-is-executing-code/45406217#45406217 – user2288580 Jul 31 '17 at 01:08
5

Well i do it some thing like this.

        NormalWaitDialog/*your wait form*/ _frmWaitDialog = null;


        //Btn Load Click Event
        _frmWaitDialog = new NormalWaitDialog();
        _frmWaitDialog.Shown += async (s, ee) =>
        {
            await Task.Run(() =>
           {
               // DO YOUR STUFF HERE 
               // And if you want to access the form controls you can do it like this
               this.Invoke(new Action(() =>
               {
                   //here you can access any control of form you want to access from cross thread! example
                   TextBox1.Text = "Any thing!";
               }));

               //Made long running loop to imitate lengthy process
               int x = 0;
               for (int i = 0; i < int.MaxValue; i++)
               {
                   x += i;
               }

           }).ConfigureAwait(true);
            _frmWaitDialog.Close();
        };
        _frmWaitDialog.ShowDialog(this);
4

You can take a look at my splash screen implementation: C# winforms startup (Splash) form not hiding

Community
  • 1
  • 1
Grzenio
  • 35,875
  • 47
  • 158
  • 240
3

The best approach when you also have an animated image is this one:

1- You have to create a "WaitForm" that receives the method that it will executed in background. Like this one

public partial class WaitForm : Form
{
    private readonly MethodInvoker method;

    public WaitForm(MethodInvoker action)
    {
        InitializeComponent();
        method = action;
    }

    private void WaitForm_Load(object sender, EventArgs e)
    {
        new Thread(() =>
        {
            method.Invoke();
            InvokeAction(this, Dispose);
        }).Start();
    }

    public static void InvokeAction(Control control, MethodInvoker action)
    {
        if (control.InvokeRequired)
        {
            control.BeginInvoke(action);
        }
        else
        {
            action();
        }
    }
}

2 - You can use the Waitform like this

private void btnShowWait_Click(object sender, EventArgs e)
{
    new WaitForm(() => /*Simulate long task*/ Thread.Sleep(2000)).ShowDialog();
}
1

or if you don't want anything fancy like animation etc. you can create a label and dock it to form then change it's z-index from document outline window to 0 and give it a background color so other controls wont be visible than run Application.DoEvents() once in form load event and do all your coding in form shown event and at the and of shown event set your label visible property to false then run Application.DoEvents() again.

trksyln
  • 136
  • 10
0

I know it is wery late, but I fonded this project and I would like to share with you, it is very usefull and sample Simple Display Dialog of Waiting in WinForms

ajd.nas
  • 354
  • 2
  • 12