Форма Windows Forms зависает после вызова шоу из другого потока - PullRequest
3 голосов
/ 11 октября 2011

У меня есть приложение, в котором есть сетевой код, который работает асинхронно.Я прикрепил некоторые события, которые будут выброшены, когда нет соединения с сервером, и я создаю некоторую форму «операция не удалась», когда это происходит.Проблема в том, что моя форма висит после создания.Я читал об этом, и я пытался сделать с:

public void ShowView()
{
    if (this.InvokeRequired)
    {
        Action a = new Action(ShowView);
        this.Invoke(a);
    }
    else this.Show();
}

И проблема все еще присутствовала.Затем я обнаружил, что если элемент управления не был создан, InvokeRequired возвращает значение false.Поэтому я при своем коде инициализации добавил:

this.show();
this.hide();

Таким образом, это похоже на работу.Но это довольно уродливо, и когда мое приложение запускается, я на мгновение вижу, как отображается моя форма, а затем исчезает.Как мне создать форму для создания всех элементов управления без ее отображения, или есть какое-то лучшее решение этой проблемы?

РЕДАКТИРОВАТЬ: Дополнительная информация.Я использую шаблон проектирования MVP.У меня есть Ведущий, которые имеют зависимость от IView.Моя форма реализует IView.В IView есть методы ShowView () и HideVIew (), которые я вызываю у своего докладчика.Мой докладчик получает событие из другого потока.Так, где я должен делать этот поток прыжков или как я должен решить это?

EDIT2: Вот пример приложения, иллюстрирующего проблему:

public partial class Form1 : Form
    {
        Form2 form;

        public Form1()
        {
            InitializeComponent();
            form = new Form2();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //form.Show();
            //form.Hide();
            Thread t = new Thread(new ThreadStart(ShowForm2));
            t.Start();
        }

        private void ShowForm2()
        {
            if (form.InvokeRequired)
            {
                Action a = new Action(ShowForm2);
                form.Invoke(a);
            }
            else
            {
                form.Show();
                Thread.Sleep(5000);
            }
        }
    }

Можете ли вы сказать мне по этой конкретной проблеме, что изменить?

Ответы [ 3 ]

4 голосов
/ 10 февраля 2012

В качестве первого шага удалите рекурсию из ShowForm2 (), используя:

Action a = new Action(() => form.Show());

Теперь подробное объяснение того, что происходит: когда эти строки комментируются в button1_Click ()

    //form.Show();
    //form.Hide();

тогда в форме ShowForm2 (). InvokeRequired будет ложным. Это означает, что форма выполняется в том же потоке, что и ваша работа, и поэтому форма "зависает".

Но когда вы раскомментируете эти строки, тогда будет та же форма. InvokeRequired будет иметь значение true, что означает, что форма выполняется в потоке пользовательского интерфейса, и именно поэтому form2 отзывчива.

Решение состоит в том, чтобы заставить form2 работать в потоке пользовательского интерфейса, но вы не хотите мерцания, как в вашем примере, поэтому вы должны попробовать это другим способом.

Решение - использовать свойство form.Handle после создания формы. Form.Handle создается при первом использовании. В вашем случае это было в форме. Show (). Очевидно, что важно создавать дескриптор в нужной теме, а не только в форме обертки. Я приложу модифицированный код, чтобы сделать вещи более ясными.

Я не уверен, что объяснение правильное, но handle = form.Handle; исправит вашу проблему.

public partial class Form1 : Form
{
    Form form;
    IntPtr handle;

    public Form1()
    {
        InitializeComponent();
        form = new Form();
        handle = form.Handle;
    }

    private void ShowForm2()
    {
        if (form.InvokeRequired)
        {
            Action a = new Action(() => form.Show());
            form.Invoke(a);
        }
        else
        {
            form.Show();
            Thread.Sleep(5000);
        }
    }

    private void button1_Click_1(object sender, EventArgs e)
    {
        //form.Show();
        //form.Hide();
        Thread t = new Thread(new ThreadStart(ShowForm2));
        t.Start();
    }
    }
2 голосов
/ 11 октября 2011

Дескриптор окна будет создан во время Show-call. Поэтому всегда хорошо показывать формы в основном потоке пользовательского интерфейса! Просто переключитесь на этот поток и затем вызовите Show ().

1 голос
/ 11 октября 2011

Ваше понимание Invoke и InvokeRequired немного не в порядке;InvokeRequired вернет true в любое время доступ к элементу управления из потока, отличного от потока, в котором он был создан (обычно называемого «потоком пользовательского интерфейса»).

Так что если выВы пытаетесь позвонить Show() или Hide() из другого потока, вам действительно нужно Invoke it.

Кроме этого краткого объяснения, вы не предоставили достаточно информации, чтобы действительно предложить какую-либо другуюидеи.Может быть, вы можете опубликовать какой-то соответствующий код, например любой код, который выполняется при загрузке или активации формы.

РЕДАКТИРОВАТЬ

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

Один из способов сделать это, если у вас есть MainForm"это всегда видно, вы можете переместить ваш метод ShowView в эту форму и использовать шаблон InvokeRequired` Invoke`, чтобы сохранить работу в потоке пользовательского интерфейса.

Другой вариант - установить *От 1026 * до Minimized по умолчанию, чтобы при первоначальном отображении (при запуске приложения) его не было видно на экране (вы также можете установить для ShowInTaskbar значение false).Тогда ваш метод ShowView также может изменить WindowState.

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