question

VAer-4038 avatar image
0 Votes"
VAer-4038 asked cooldadtx answered

How to solve form.Show delay issue?

This is the code in ChildForm1:

ChildForm2.Show();
this.Close(0

At this step, ChildForm2 should show and ChildForm1 should close.

This is the code in ChildForm2_Load:

private void ChildForm2_Load (object sender, EventArgs e)
{
generate combo box dropdown list items;

MessageBox.Show("Hello, world, this is ChildForm2.");

}



The issue is: When I see the messgebox, ChildForm1 still displays in the screen, and no ChildForm2 there. Only after I click Ok on the message box, then message box disappears, ChildForm2 closes, ChildForm2 shows up.

windows-forms
· 5
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Presumably you don't need to show that MessageBox, it's only for your diagnosis?
If you remove it, do you have an issue?

Have you tried hiding form1 before showing form2?

0 Votes 0 ·

ChildForm2_Load only has the code to generate combo box dropdown list items and display a messagebox to user. Removing messagebox does solve the problem, but that is not what I want.

I prefer to have messagebox in ChildForm2_Load, which explains something about ChildForm2. Since the messagebox refers to ChildForm2, I would like to have ChildForm2 on the screen when user sees the messgebox.

0 Votes 0 ·

If you want form2 showing, then you need to defer showing the message box. Use a timer as suggested by cooldadtx

0 Votes 0 ·
Show more comments
cooldadtx avatar image
0 Votes"
cooldadtx answered VAer-4038 edited

Show is a blocking call. The Load event is raised before the form is rendered the first time. Hence the user has to dismiss the message box before the form is actually told to paint itself and hence show up on the screen.

There are different ways to handle this problem depending upon how you want your UI to behave. Personally I would say just remove the message box. It looks like a test message anyway. Problem will then be solved.

If you have a more realistic app such that you might need to display a message, such as for error handling, then you need to move the message until after the form is displayed. If your form initialization (that generate combo code you didn't show) takes a while then have it run after the form is loaded. In your Load handler disable any controls that cannot be used until the data is loaded. When the form loads the user will see a disabled UI. After the form is shown then load the data and optionally display a message box. This is often done using a simple WInforms timer set to be raised only once. Since Winforms timers use the message queue they will not be raised until after the form is rendered the first time. When the timer elapses load your data and reenable any controls you disabled in load. This is equivalent to the "Please wait" style UIs you see floating around today.

Another alternative is to use the BackgroundWorker component in the Load method. Have it start its work in Load handler. It will do any non-UI stuff on a background thread. Have the form handle the RunWorkerCompleted event, which should raise after the form is loaded. Inside the completed handler you can update the UI and display any message box you have. If it might take a while consider also handling the ProgressChanged event from BWC and update the UI periodically.

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

After the form is shown then load the data and optionally display a message box. This is often done using a simple WInforms timer set to be raised only once.

How to do that? I do want user to see a message when seeing ChildForm2, the message displays some information related to ChildForm2

Thanks.



0 Votes 0 ·
cooldadtx avatar image
0 Votes"
cooldadtx answered

Create a timer that fires 500 ms or so after it is set. Since a Winforms timer runs on the UI thread it should fire after the form is painted which gives you what you want. You might need to adjust the numbers a little.

csharp
//Not tested
public MyForm () 
{
   InitializeComponent();

   //Should really set this up using the designer...
   _timer = new System.Windows.Forms.Timer();
   _timer.Enabled = false;
   _timer.Interval = 500;  // 500 ms
   _timer.Tick += OnStartupTimer;
}

//Note that I always recommend overriding OnLoad and not handling the Load event but if you prefer Load event then the code is the same
protected override void OnLoad ( EventArgs e )
{
   base.OnLoad();  

   //Start timer
   _timer.Start();
}

private void OnStartupTimer ( object sender, EventArgs e )
{
   //Don't let timer run again - if this call takes to long might need to add reentrancy check
   _timer.Stop();
   
   //Form should be shown, do what you want
}

private readonly Timer _timer;


This may be sensitive to timing so you might also consider using BackgroundWorker instead. The same basic setup would occur. The difference is that you'd start the background worker instead. This would be the way I'd go if you need to do lengthy work after the form is shown, such as loading data.

csharp
//Not tested
public MyForm () 
{
   InitializeComponent();

   //Should really set this up using the designer...
   _startupWorker = new System.ComponentModel.BackgroundWorker();
   _startupWorker.WorkerReportsProgress = true;
   _startupWorker.DoWork += OnStartupWork;
   _startupWorker.RunWorkerCompleted += OnStartupWorkCompleted;
   _startupWorker.ProgressChanged += OnStartupWorkProgress;
}

//Note that I always recommend overriding OnLoad and not handling the Load event but if you prefer Load event then the code is the same
protected override void OnLoad ( EventArgs e )
{
   base.OnLoad();  

   //Start worker
   _startupWorker.RunWorkerAsync();
}

private void OnStartupWork ( object sender, DoWorkEventArgs e )
{
   var worker = sender as BackgroundWorker;

   // (Optional) Do lengthy work

   //Notify UI - pass whatever data you want
   worker.ReportProgress(0, "Message to show");

   // (Optional) Do more work
}

//If you want to do post-work stuff on the UI then put it here otherwise remove this
private void OnStartupWorkCompleted ( object sender, RunWorkerCompletedEventArgs e )
{
}

private void OnStartupWorkProgress ( object sender, ProgressChangedEventArgs e )
{
   //On UI thread so do whatever you want

   //If progress is 0 then display message...
   if (e.ProgressPercentage == 0)
      MessageBox.Show(e.UserState as string);
}

private readonly BackgroundWorker _startupWorker;
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.