Hello All:
I was wondering how do I implement a popup window in my C# Windows form that will tell the user "Loading Data....Please Wait" until a form has completed loading data?
At times, it can take 5 - 10 seconds for a page to fully load, and if a user tries to do something, can cause the form to crash, so I want to place a popup window that keeps the user from doing anything until it completes loading, then once it completes loading, goes away and gives control back to the user.
I am not sure what to search for when Googling this, so my Net searches are not that useful. If anyone is able to help or point me in some direction, I would greatly appreciate some help.
Thanks
Andy |
| am1234 Thursday, March 06, 2008 3:53 PM |
You first have to determine when the load is complete. This should done with a backgroundworker. Use the DoWork Event to load the data, display the "Wait" form and disable the main form. Use the WorkComplete event of teh backgroundworker to dispose the "Wait" form and enable the main form.
Adam |
| Adam D. Turner Thursday, March 06, 2008 5:12 PM |
What I did to solve this was: I used the backgroundworker as Adam described, but since the main data load was being called from an outside process, I set the .RunWorkerAsync in the _Load and then loaded the Wait form in the DoWork event. Since I didn't know though when the data would be technically completed, I just call the
backgroundWorker1_RunWorkerCompleted(null, null); from the method that is loading the data which then calls the close of the Wait form. I am not sure if this is technically the best method, but it seems to be working. |
| am1234 Friday, March 07, 2008 6:26 PM |
you can create a splash form or maybe you can show a progress form using Show() then hide the original form until it's loaded. |
| H. _冬_ Tony Thursday, March 06, 2008 4:50 PM |
You first have to determine when the load is complete. This should done with a backgroundworker. Use the DoWork Event to load the data, display the "Wait" form and disable the main form. Use the WorkComplete event of teh backgroundworker to dispose the "Wait" form and enable the main form.
Adam |
| Adam D. Turner Thursday, March 06, 2008 5:12 PM |
Adam:
Thanks for the advice. One question I have though: my form isn't being loaded by the traditional "form_Load" event. So I am not sure how to us the .DoWork event you are talking about in the BackgroundWorker.
The data is loaded when this line is called:
VerixClientMain.formTerminalSettings.giveSettingsThroughXML( moNode.ChildNodes.Item(1).InnerXml, moNode.ChildNodes.Item(2).InnerXml );
in a the main class, thereby loading the data in the exposed form. This method is declared as such in the exposed form.
public void giveSettingsThroughXML(string psCurrentXML, string psFutureXML)
{
if(this.InvokeRequired)
{
myMethodDelegate toMyMethodInvoker = new myMethodDelegate(giveSettingsThroughXML);
this.Invoke( toMyMethodInvoker, new string[]{ psCurrentXML, psFutureXML } );
}
else
{
//---------------------------------------------------------------------------------
// Load values
//---------------------------------------------------------------------------------
moTerminalSettings.LoadCurrentDataFromXML(psCurrentXML);
moTerminalSettings.LoadFutureDataFromXML(psFutureXML);
setupOperatorPasscodeIDs();
//---------------------------------------------------------------------------------
// Populate the fields properly based on the loaded data
//---------------------------------------------------------------------------------
populateSettingFields();
validateTabPage(tabReports);
this.Show();
this.BringToFront();
if (!this.mbLockedTerminal)
{
MessageBox.Show("another user has settings locked");
}
}
} //public void giveSettingsThroughXML(string psCurrentXML, string psFutureXML)
So I am a little unsure how to do this.
Thanks
Andy |
| am1234 Thursday, March 06, 2008 6:59 PM |
Ok so put that instantion inside the backgroundworker DoWork Event:
static void backgroundworker1_DoWork (object sender, DoWorkEventArgs e) {
VerixClientMain.formTerminalSettings.giveSettingsThroughXML( moNode.ChildNodes.Item(1).InnerXml, moNode.ChildNodes.Item(2).InnerXml );
//Show your wait form here
}
static void backgroundworker1_RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e) {
//dispose your wait form here } Adam |
| Adam D. Turner Thursday, March 06, 2008 7:55 PM |
Hi,
Here is a example code showing how your problem can be solved :
public partial class MainForm : Form { public MainForm() { InitializeComponent(); }
// This function is executed in another thread, it sleeps 5 seconds and closes the 'Wait Form'. void WasteTime(Object arg) { Thread.Sleep(5000); Form frm = arg as Form; if (frm != null) { this.Invoke(new MethodInvoker(delegate() { frm.Close(); })); } }
private void Form2_Load(object sender, EventArgs e) { WaitForm LoadForm = new WaitForm(); // Create a 'Wait Form' Thread ProcessThread = new Thread(new ParameterizedThreadStart(WasteTime)); // Create a thread ProcessThread.Start(LoadForm); // Start the thread and pass the 'Wait Form' to it so the Thread can close it. LoadForm.ShowDialog(); // Show the 'Wait Form' as Modal Dialog so the main form is blocked. } }
public partial class WaitForm : Form { public WaitForm() { InitializeComponent(); } }
Here, I invoke a function on another thread and pass the reference to 'Wait Form' which is blocking the 'Main Form', so the thread can close the 'Wait Form' after it's done with own processing (sleeping for 5 seconds in this example).
I hope this helps.
|
| decyclone Thursday, March 06, 2008 8:02 PM |
Threading is a step in the right direction but the Thread.Sleep is a definite no no simply because the timing will intermittently cause the application to crash...yes you can sleep longer but this is horrible practice.
The backgroundworker is the best solution and it's the typical and standard solution to this problem.
Adam |
| Adam D. Turner Thursday, March 06, 2008 8:09 PM |
Hi Adam,
The call to Thread.Sleep is just to emulate long processing described by Andy. And it's just an example, so, I don't see any 'horrible practice' using it.
|
| decyclone Thursday, March 06, 2008 8:17 PM |
Hi decyclone,
Yes I understand the emulation and it has its place. I would agree with your approach if data wasn't being loaded which makes the timing undetermined. Thread.Sleep might 'unsleep' in the middle of the data load and give access to the form which the OP doesn't want...or 'unsleep' long after the load is complete. Either way, not a very good approach to this 'specific' problem.
The bw will create the thread, monitor the progress, and precisely execute the code when the load is complete. The class also offers a wide array of additional functionality that really comes in handy.
Adam |
| Adam D. Turner Thursday, March 06, 2008 8:27 PM |
Hi Adam,
I think you are not getting it yet. In my example, the WasteTime function is the main processing function (like in andy's case, some function that calls 'giveSettingsThroughXML' which takes 5 to 10 seconds time). It's not that I am waiting for 5 seconds for some other task to complete and then close the form. Sleeping 5 seconds is the task in my example and the thread I create is the worker thread. You just need to place the processing code (in andy's case, the xml processing code) in place of the call to Sleep function and you are done.
The solution is simple. You create a 'Wait Form'. You pass it's reference to the Thread or BW which is doing some lengthy task. You start the thread and open the form as Modal Dialog. After the other thread is through with the lengthy task, it closes the 'Wait Form' so that the 'Main Form' is back in control.
I am not surprized with your obsession with BackgroundWorker, and there is nothing wrong with it. It's simpler to understand, too. It's just I like working with Thread class better.
I hope you get it this time.
|
| decyclone Thursday, March 06, 2008 8:49 PM |
Adam:
Thank you for the response (I have appreciated all your help), but why this doesn't work for me (it might work, but could be my lack of understanding), is that this method is not on my page where my backgroundworker is being set, so I can't put the instantion inside that.
That is a call from another form to the form where my backgroundworker is set, and what is setting off the population of the form (if that makes sense).
So I have form VerixMain that has a datagrid. I rightmouse click on it and say "show settings." Once I do that, an event is fired that goes out to the host, gets an XML file gives it to the VerixClientMain. This then more or less is calling the method on the Settings page which running the backgroundworker.
On VerixMain: we have
VerixClientMain.formTerminalSettings.giveSettingsThroughXML( moNode.ChildNodes.Item(1).InnerXml, moNode.ChildNodes.Item(2).InnerXml );
Calling the function method on Settings (which then loads the data)
public void giveSettingsThroughXML( string psCurrentXML, string psFutureXML )
{
if( this.InvokeRequired )
{
myMethodDelegate toMyMethodInvoker = new myMethodDelegate( giveSettingsThroughXML );
this.Invoke( toMyMethodInvoker, new string[]{ psCurrentXML, psFutureXML } );
}
else
{
//Load values
moTerminalSettings.LoadCurrentDataFromXML( psCurrentXML );
moTerminalSettings.LoadFutureDataFromXML( psFutureXML );
setupOperatorPasscodeIDs();
//Populate the fields properly based on the loaded data
populateSettingFields();
validateTabPage( tabReports );
this.Show();
this.BringToFront();
if( !this.mbLockedTerminal )
MessageBox.Show( "another user has settings locked" );
formLoaded = true;
}
}
So I am not sure how I can place the
VerixClientMain.formTerminalSettings.giveSettingsThroughXML( moNode.ChildNodes.Item(1).InnerXml, moNode.ChildNodes.Item(2).InnerXml ) inside the instantion of the backgroundworker.DoWork event and get this to work. |
| am1234 Thursday, March 06, 2008 9:06 PM |
What I did to solve this was: I used the backgroundworker as Adam described, but since the main data load was being called from an outside process, I set the .RunWorkerAsync in the _Load and then loaded the Wait form in the DoWork event. Since I didn't know though when the data would be technically completed, I just call the
backgroundWorker1_RunWorkerCompleted(null, null); from the method that is loading the data which then calls the close of the Wait form. I am not sure if this is technically the best method, but it seems to be working. |
| am1234 Friday, March 07, 2008 6:26 PM |
Yes this will work fine. We wouldn't have been able to pin point the exact approach with the given code.
...but thanks for not marking my suggestion as an answer...lol
Adam |
| Adam D. Turner Friday, March 07, 2008 6:39 PM |
Adam:
I did mark it as an answer and it helped me (i was not aware I could mark two, I only thought I could mark the final solution, my apologies), because without your suggestion, I woudl never have been able to solve it. I really do appreciate your help, I didn't mean to slight your help in any way, as it was much appreciated and very much helped in solving my needs.
Thanks
Andy
|
| am1234 Friday, March 07, 2008 6:48 PM |
I was being facetious.
Your solution will work fine.
Happy coding,
Adam |
| Adam D. Turner Friday, March 07, 2008 7:01 PM |