Quick question: Is it possible to showDialog/Show form from a new thread that has been started from within Load event of a different form?
EDIT: Why is it not possible to showDialog/Show form from a new thread that has been started from within Load event of a different form?
The supposed requirement is to show a loader form /spiral thingy with loading text, and possibly more/ while MDI child form is loading thus hanging the whole application.
The requirement states that the "Loader form" must not hang. Thus it requires a new thread.
code summary, that I have implemented so far: MDI Parent:
delegate void ManipulateJob();
public void StartJob()
{
Cursor.Current = Cursors.WaitCursor;
if (this.InvokeRequired)
//case when the Loader is started from a different thread than the main we need to invoke
{
System.Diagnostics.Debug.WriteLine("-> MainForm.StartJob InvokeRequired");
ManipulateJob callback = new ManipulateJob(StartJob);
this.Invoke(callback, new object[] { });
}
else
{
tasks_running++;
System.Diagnostics.Debug.WriteLine("-> MainForm.StartJob InvokeNotRequired");
if ((this.t == null || !this.t.IsAlive)&&tasks_running == 1)
{
System.Threading.ThreadStart ts = new System.Threading.ThreadStart(StartDifferent);
this.t = new System.Threading.Thread(ts);
this.t.Name = "UI Thread";
System.Diagnostics.Debug.WriteLine(" **starting thread");
this.t.Start();
while (_form==null||!_form.IsHandleCreated)
//do not continue until the loader form has been shown when this is enabled
//the whole program hangs here when StartJob is called within Load event
{
System.Threading.Thread.Yield();
}
}
}
System.Diagnostics.Debug.WriteLine("<- MainForm.StartJob");
}
private static frmLoading _form;
public void StartDifferent()
{
System.Diagnostics.Debug.WriteLine(" **thread started");
_form = new frmLoading();
System.Diagnostics.Debug.WriteLine(" **loader created");
_form.Icon = this.Icon;
System.Diagnostics.Debug.WriteLine(" **loader icon set");
_form.ShowDialog();
System.Diagnostics.Debug.WriteLine(" **thread terminating");
}
public void StopJob()
{
if (this.InvokeRequired) //in case this is called from a different thread
{
System.Diagnostics.Debug.WriteLine("-> MainForm.StopJob InvokeRequired");
ManipulateJob callback = new ManipulateJob(StopJob);
this.Invoke(callback, new object[] { });
}
else
{
System.Diagnostics.Debug.WriteLine("-> MainForm.StopJob InvokeNotRequired");
if (tasks_running>0&&--tasks_running == 0)
{
StopDifferent();
}
}
System.Diagnostics.Debug.WriteLine("<- MainForm.StopJob");
Cursor.Current = Cursors.Default;
}
delegate void CloseLoadingForm();
public void StopDifferent()
{
System.Diagnostics.Debug.WriteLine("-> MainForm.StopDifferent");
try
{
if (_form != null && _form.IsHandleCreated)
{
CloseLoadingForm callback = new CloseLoadingForm(_form.Close);
//_form itself is always on a different thread thus, invoke will always be required
_form.Invoke(callback);
}
}
finally
{
try
{
if (this.t != null && this.t.ThreadState == System.Threading.ThreadState.Running)
this.t.Join();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(" MainForm.StopDifferent t.Join() Exception: " + ex.Message);
}
}
System.Diagnostics.Debug.WriteLine("<- MainForm.StopDifferent");
}
child form example:
private void frmPricingEvaluationConfig_Load(object sender, EventArgs e)
{
//taking out the following and putting it before
//Form frm = new Form();
//frm.Show(); works
if (this.MdiParent is IThreadedParent)
{
((IThreadedParent)this.MdiParent).StopJob();
}
// the loader form is not displayed yet
System.Diagnostics.Debug.WriteLine(" loading pricingEvaluationConfig");
loadPricingClasses();
loadEvaluationClasses();
if (this.MdiParent is IThreadedParent)
{
((IThreadedParent)this.MdiParent).StopJob();
}
}
//loader form displays here, but is unable to close because the closing has been called
please don't mind the namings and the fact that there are 2 matching sets of start and stop.
the question is whenever i call Startjob from within a form1_Load(object sender, EventArgs e) the _form (AKA loader) is not displayed until the Load method finishes.
EDIT: In other words, the Loader does not display until the actual form is displayed, the only time the Loader is "Shown" (displayed on screen) is when the actual form is finished the onLoad method. :ENDEDIT
if i take out the Startjob out of the load handler method and put it before I declare and Show() then everything works the way it supposed to
EDIT:
I assume, without any proof, that Form's CreateHandle() method that is called within ShowDialog() and Show() methods accesses a static property somewhere checking whether any handles are already being created, and if so it stacks its own creation after the current Handle Creation, because during this whole thing somewhere the code tried to Close() the Loader/Splash and threw an error saying "Cannot Close() a form that is Creating Handle." So I assumed the CreateHandle() method has somewhere something similar to my
while() { Thread.Yield(); }
thus creating 2 threads /1 of which is the Loader\Splash creator thread/ which continuously Yield to one another.
Basically, I don't understand why all of this is happening, if my assumptions are correct why should Forms should queue after one another? :ENDEDIT
I will gladly answer all questions and concerns about the code, please ask if anything I'm doing here is vague, or you don't quite understand the need of it.