Создание новой формы из нового потока, начатого в событии Load другой формы - PullRequest
0 голосов
/ 14 марта 2012

Быстрый вопрос: возможно ли показать диалог / Показать форму из нового потока, который был запущен из события Load другой формы?

РЕДАКТИРОВАТЬ: Почему невозможно показатьDialog / Показать форму из нового потока, который был запущен из события Load другой формы?

Предполагаемое требование - показать загрузочную форму / спираль с загрузкой текста и, возможно, больше / во время загрузки дочерней формы MDI, что приведет к зависанию всего приложения.

Требование гласит, что «Форма загрузчика» не должна висеть. Таким образом, требуется новая тема.

Сводка кода, которую я реализовал до сих пор: 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");
}

пример дочерней формы:

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

пожалуйста, не обращайте внимания на названия и тот факт, что есть 2 подходящих набора начала и конца.

Вопрос заключается в том, что всякий раз, когда я вызываю Startjob из form1_Load (отправитель объекта, EventArgs e), _form (загрузчик AKA) не отображается, пока не завершится метод Load.

EDIT: Другими словами, загрузчик не отображается до тех пор, пока не отобразится фактическая форма, единственный раз, когда загрузчик «показан» (отображается на экране), это когда фактическая форма завершена, метод onLoad. : EndEdit

если я вычитаю Startjob из метода обработчика загрузки и помещаю его перед объявлением и Show (), тогда все работает так, как и предполагалось

EDIT:
Я предполагаю, без каких-либо доказательств, что метод CreateHandle () формы, который вызывается в методах ShowDialog () и Show (), получает доступ к статическому свойству где-нибудь, проверяя, были ли уже созданы какие-либо дескрипторы, и если это так, он складывает свое собственное создание после текущего Создание дескриптора, потому что во время всего этого кода где-то код пытался закрыть () загрузчик / всплеск и выдал ошибку, говорящую «Не удается закрыть () форму, создающую дескриптор». Поэтому я предположил, что метод CreateHandle () имеет нечто похожее на мой

while() { Thread.Yield(); } 

Таким образом создаются 2 потока / 1 из которых является потоком создателя Loader \ Splash /, которые непрерывно уступают друг другу.

В принципе, я не понимаю, почему все это происходит, если мои предположения верны, почему формы должны стоять в очереди друг за другом? : EndEdit

Я с радостью отвечу на все вопросы и замечания по поводу кода, пожалуйста, спросите, если что-то, что я здесь делаю, расплывчато, или вы не совсем понимаете необходимость этого.

1 Ответ

1 голос
/ 14 марта 2012

Похоже, более подходящим решением является выполнение длительной задачи инициализации в отдельном потоке и включение дочернего окна MDI после завершения инициализации (поэтому можно завершить создание дочернего окна MDI, но отключить или оставить окно невидимо, пока не завершится отдельный поток загрузчика. Включите заставку или сделайте видимым дочернее окно после завершения загрузки).

Я не уверен, правильно ли я следую вашему текущему коду, но кажется, что вы блокируете событие OnLoad. Это предотвратит очередь сообщений Windows, которая, в свою очередь, заблокирует отображение любого пользовательского интерфейса для приложения.

Затем можно использовать любое решение для заставки WinForms до тех пор, пока поток, выполняющий загрузку, не завершится, например,

http://www.codeproject.com/Articles/5454/A-Pretty-Good-Splash-Screen-in-C

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...