使用WPF中的Backgroundworker为主应用程序弹出MessageBox

在WPF应用程序中,我使用BackgroundWorker定期检查服务器上的条件。 虽然工作正常,但我希望弹出一个MessageBox,如果在检查过程中出现故障,请通知用户。

这就是我所拥有的:

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"); } 

调用ReportProgress并将其传递给MessageBox.Show

它不仅不会阻挡主窗口,它也很可能在它后面消失。 这是它在不同线程上运行的直接结果。 如果没有为消息框指定所有者,那么它将使用GetActiveWindow()API函数寻找一个所有者。 它只考虑使用相同消息队列的窗口。 这是一个特定于线程的属性。 当然,丢失消息框很难处理。

同样,MessageBox仅禁用属于同一消息队列的窗口。 因此不会阻止主线程创建的窗口。

通过让UI线程显示消息框来解决您的问题。 使用Dispatcher.Invoke或利用ReportProgress或RunWorkerCompleted事件。 听起来不像这里的事件是合适的。

更换

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

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

这将导致消息框位于主线程上,并将阻止对UI的所有访问,直到它获得响应。 作为额外的奖励this.Invoke将返回一个可以投射到DialogResult的对象。

正如Stephen和Hans所说,使用ReportProgress事件,并将数据传递给UI线程。 如果您想要对MessageBox执行任何操作(对于isntance,更新控件),这一点尤其重要,因为后台线程无法直接执行此操作。 你会得到一个跨线程的例外。

所以无论你需要做什么(更新进度条,将消息记录到UI等),都要将数据传递给UI线程,告诉UI线程需要做什么,但让UI线程去做。

我这样修改它并且对我来说很好

  return Application.Current.Dispatcher.Invoke(() => MessageBox.Show(messageBoxText, caption, button, icon));