Должен ли я вызывать (), чтобы показать диалог или MessageBox из потока? - PullRequest
8 голосов
/ 09 августа 2011

Я выполняю код в рабочем потоке. Иногда мне нужно показать диалог или сообщение.

Я играл с кодом, и, кажется, он строго необходим Invoke только когда я передаю IWin32Window в диалог. В остальном работает нормально.

У меня два вопроса:

  1. Должен ли я позвонить с Invoke?
  2. Какие риски у меня возникают, если я показываю диалоговое окно или окно сообщения без Invoke?

Заранее спасибо

Ответы [ 3 ]

11 голосов
/ 09 августа 2011

Это небольшая ошибка в Winforms. Он содержит диагностический код в получателе свойства Handle, который проверяет, используется ли свойство в том же потоке, что и тот, который создал дескриптор. Хотя это чрезвычайно полезно для диагностики ошибок в потоках, это не всегда уместно. Один из таких случаев здесь, Windows фактически не требует, чтобы родительский элемент окна принадлежал тому же потоку.

Вы можете обойти эту проблему, вызвав функцию SetParent () или временно отключив проверку с помощью Control.CheckForIllegalCrossThreadCalls. Или с помощью Control.Invoke (), лучший способ. не обходите его, не указывая владельца. В отсутствие другого окна владельцем диалога является окно рабочего стола. Он не будет иметь отношения Z-порядка с другими окнами, у которых рабочий стол является их владельцем. И это заставит диалоговое окно иногда исчезать за другим окном, совершенно недоступным для пользователя.

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

1 голос
/ 09 августа 2011

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

Редактировать: Чтобы проверить это, следующий код просто создаетновый поток и окно сообщения показа оттуда, где в потоке пользовательского интерфейса, создающем второе сообщение в то же самое время с указанием владельца, чтобы быть формой, оба сообщения обнаруживаются без любой проблемы:

private void button1_Click(object sender, EventArgs e)
{
    new Thread(() =>
    {
        MessageBox.Show("Hello There!");
    }) { IsBackground = true }.Start();

    Thread.Sleep(1000);

    if (MessageBox.Show(this, "Hi", "Jalal", MessageBoxButtons.YesNo) == 
        System.Windows.Forms.DialogResult.Yes)
    {
        return;
    }
}
0 голосов
/ 09 августа 2011

Когда мне нужно взаимодействовать с некоторыми элементами управления, созданными в главном потоке из другого потока, я использую BackgroundWorker. Это событие называется OnProgressChange. Поэтому, возможно, попробуйте создать этот объект BackgroundWorker в основном потоке, а в методе DoWork просто запустите это событие, затем присоединенный к нему метод будет выполнен в основном потоке, так что у вас есть доступ ко всем элементам управления.

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