I am working on a WPF application. I have a time consuming method that I want to run async via BackgroundWorker
. While the method runs, I want to display a modal "Please Wait..." dialog window, which must automatically close when the BackgroundWorker
completes.
I currently have very little experience with BackgroundWorker
or any multi threaded programming.
The code below currently results in an InvalidOperationException
, with the message "The calling thread must be STA, because many UI components require this."
Please advise me on how to achieve what I am trying to achieve, and extra brownie-points if you can help me understand what is going wrong.
Many thanks!
EDIT
Just to clarify - The idea is that the main thread launches the BackgroundWorker
, then shows the modal dialog. When the worker completes, it closes the modal dialog. When the modal dialog closes, the main thread continues.
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();
}
}
You can't call ShowDialog from the BackgroundWorker. You have to use the Dispatcher to ask the UI thread to execute it:
The 'Completed' event of the BackgroundWorker is executed in the UI thread, so this part should be fine.