在BackgroundWorker运行时显示模式窗口,而不会出现STA/MTA问题
本文关键字:STA 问题 MTA 运行时 BackgroundWorker 显示 模式 窗口 | 更新日期: 2023-09-27 18:19:51
我正在开发一个WPF应用程序。我有一个耗时的方法,我想通过BackgroundWorker
运行异步。当该方法运行时,我想显示一个模式的"Please Wait…"对话框窗口,该窗口必须在BackgroundWorker
完成时自动关闭。
我目前对BackgroundWorker
或任何多线程编程都没有什么经验。
下面的代码当前导致InvalidOperationException
,并显示消息"调用线程必须是STA,因为许多UI组件都需要它。"
请告诉我如何实现我想要实现的目标,如果你能帮助我理解哪里出了问题,还可以获得额外的布朗尼积分。
非常感谢!
编辑只是澄清一下——这个想法是主线程启动BackgroundWorker
,然后显示模式对话框。当工作程序完成时,它将关闭模式对话框。当模式对话框关闭时,主线程继续。
public class ImageResizer
{
private BackgroundWorker worker;
private MemoryStream ImageData { get; set; } // incoming data
private public MemoryStream ResizedImageData { get; private set; } // resulting data
private Dialogs.WorkInProgressDialog ProgressDialog;
// Public interface, called by using class:
public MemoryStream ReduceImageSize(MemoryStream imageData)
{
// injected data:
this.ImageData = imageData;
// init progress dialog window:
ProgressDialog = new Dialogs.WorkInProgressDialog();
// Start background worker that asyncronously does work
worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
// Show progress dialog. Dialog is MODAL, and must only be closed when resizing is complete
ProgressDialog.ShowDialog(); // THIS LINE CAUSES THE INVALID OPERATION EXCEPTION
// This thread will only continue when ProgressDialog is closed.
// Return result
return ResizedImageData;
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
// Call time consuming method
ResizedImageData = ReduceImageSize_ActualWork();
}
// The actual work method, called by worker_DoWork
private MemoryStream ReduceImageSize_ActualWork()
{
// Lots of code that resizes this.ImageData and assigns it to this.ResizedImageData
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Async work completed - close progress dialog
ProgressDialog.Close();
}
}
您不能从BackgroundWorker调用ShowDialog。您必须使用Dispatcher来请求UI线程执行它:
this.Dispatcher.BeginInvoke(new Action(() => ProgressDialog.ShowDialog()));
BackgroundWorker的"Completed"事件是在UI线程中执行的,所以这部分应该很好。