【问题标题】:Showing Modal Window while BackgroundWorker runs, without getting STA/MTA issue在 BackgroundWorker 运行时显示模态窗口,而不会出现 STA/MTA 问题
【发布时间】:2012-02-05 19:27:09
【问题描述】:

我正在开发一个 WPF 应用程序。我有一个耗时的方法,我想通过BackgroundWorker 运行异步。当方法运行时,我想显示一个模态的“请稍候...”对话框窗口,它必须在 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();
    }
}

【问题讨论】:

  • 版主,请删除我的问题 - 我收到的错误是由于不相关的编码错误造成的,因此这个问题是 A)废话和 B)对任何人都没有用。谢谢。

标签: c# wpf dialog backgroundworker


【解决方案1】:

您不能从 BackgroundWorker 调用 ShowDialog。您必须使用 Dispatcher 要求 UI 线程执行它:

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

BackgroundWorker的'Completed'事件是在UI线程中执行的,所以这部分应该没问题。

【讨论】:

  • 另外,由于 UI 线程将使用 Dispatcher.Invoke 处理 ShowDialog(),RunWorkerCompleted 中的 ProgressDialog.Close() 是否必要甚至合法?
  • 你完全正确。我误读了示例中的 cmets,不知何故认为代码只有在模式关闭后才能继续。用 BeginInvoke 替换它。然后关闭是有用且合法的,因为当后台工作人员完成其工作时,模式对话框仍将打开。
  • 谢谢@KooKiz,但我很困惑——在我提供的代码中,我没有从 BackgroundWorker 调用 ShowDialog——我调用了worker.RunWorkerAsync();,然后调用了ProgressDialog.ShowDialog();,两者都使用相同的方法。
  • @Kookiz:但您最初的假设是正确的,OP 希望后台线程仅在 对话框关闭后继续 - 请参阅评论 "// 此线程只会继续当 ProgressDialog 关闭时。”在方法 ReduceImageSize。 [也许应用程序需要重组?]
  • 是的,我在编辑中添加了一个说明 - 模态对话框从主线程启动,并在后台工作人员忙碌时阻止用户与主窗口进行交互。当worker完成后,Modal Dialog关闭,主线程继续。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
  • 1970-01-01
  • 2015-04-30
  • 1970-01-01
相关资源
最近更新 更多