Showing Modal Window while BackgroundWorker runs,

2019-02-25 03:41发布

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

1条回答
啃猪蹄的小仙女
2楼-- · 2019-02-25 04:14

You can't call ShowDialog from the BackgroundWorker. You have to use the Dispatcher to ask the UI thread to execute it:

 this.Dispatcher.BeginInvoke(new Action(() => ProgressDialog.ShowDialog()));

The 'Completed' event of the BackgroundWorker is executed in the UI thread, so this part should be fine.

查看更多
登录 后发表回答