Сование MessageBox для главного приложения с Backgroundworker в WPF

В приложении WPF я использую BackgroundWorker для периодической проверки на условие на сервере. В то время как это хорошо работает, я хочу вытолкать MessageBox notifing пользователи, если что-то перестало работать во время проверки.

Вот то, что я имею:

public static void StartWorker()
{
    worker = new BackgroundWorker();

    worker.DoWork += DoSomeWork;
    worker.RunWorkerAsync();
}

private static void DoSomeWork(object sender, DoWorkEventArgs e)
{
    while (!worker.CancellationPending)
    {
        Thread.Sleep(5000);

        var isOkay = CheckCondition();

        if(!isOkay)
           MessageBox.Show("I should block the main window");                
    }   
}

Но этот MessageBox не блокирует главное окно. Я могу все еще нажать на свое приложение WPF и изменить что-либо, что я люблю с MessageBox вокруг.

Как я решаю это?Спасибо,


Править:

Для ссылки это - то, что я закончил тем, что делал:

public static void StartWorker()
{
    worker = new BackgroundWorker();

    worker.DoWork += DoSomeWork;
    worker.ProgressChanged += ShowWarning;
    worker.RunWorkerAsync();
}

private static void DoSomeWork(object sender, DoWorkEventArgs e)
{
    while (!worker.CancellationPending)
    {
        Thread.Sleep(5000);

        var isOkay = CheckCondition();

        if(!isOkay)
           worker.ReportProgress(1);                
    }   
}

private static void ShowWarning(object sender, ProgressChangedEventArgs e)
{
    MessageBox.Show("I block the main window");
}
9
задан Chi Chan 23 June 2010 в 20:14
поделиться

4 ответа

Вызовите ReportProgress и передайте this в MessageBox.Show .

6
ответ дан 4 December 2019 в 08:50
поделиться

Он не только не блокирует главное окно, но и с большой вероятностью исчезнет за ним. Это прямое следствие того, что оно работает в другом потоке. Если вы не указали владельца для окна сообщения, то оно ищет его с помощью API-функции GetActiveWindow(). Она учитывает только те окна, которые используют одну и ту же очередь сообщений. Что является свойством, специфичным для конкретного потока. Потерять окно сообщений, конечно, довольно сложно.

Аналогично, MessageBox блокирует только те окна, которые принадлежат одной и той же очереди сообщений. И, таким образом, не блокирует окна, созданные вашим главным потоком.

Решите проблему, позволив потоку пользовательского интерфейса отображать окно сообщения. Используйте Dispatcher.Invoke или задействуйте события ReportProgress или RunWorkerCompleted. Не похоже, что события здесь уместны.

10
ответ дан 4 December 2019 в 08:50
поделиться

Замените

MessageBox.Show("I should block the main window"); 

на

this.Invoke((Func<DialogResult>)(() => MessageBox.Show("I should block the main window")));

, что приведет к тому, что окно сообщения будет находиться в основном потоке и заблокирует весь доступ к пользовательскому интерфейсу до тех пор, пока он не получит ответ. В качестве дополнительного бонуса this.Invoke вернет объект, который можно преобразовать в DialogResult.

4
ответ дан 4 December 2019 в 08:50
поделиться

Как сказали Стивен и Ханс, используйте событие ReportProgress и передавайте данные в поток UI. Это особенно важно, если вы хотите сделать что-то кроме MessageBox (например, обновить элемент управления), потому что фоновый поток не может сделать это напрямую. Вы получите межпотоковое исключение.

Поэтому, что бы вам ни нужно было сделать (обновить индикатор выполнения, записать сообщения в UI и т.д.), передайте данные потоку UI, скажите потоку UI, что нужно сделать, но пусть поток UI сделает это.

2
ответ дан 4 December 2019 в 08:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: