【问题标题】:Have BackgroundWorker wait for UI thread to show image让 BackgroundWorker 等待 UI 线程显示图像
【发布时间】:2014-01-20 15:52:43
【问题描述】:

好的,所以我有一个 WPF 应用程序,它在按下按钮时会运行如下测试列表:

  1. 在 GUI 中按下 RunTest 按钮
  2. BackgroundWorker 已创建并开始运行 DoWork(见下文):
  3. 当 t.Name == "TestSpecial" 时,我想在继续之前在 UI 中显示图像。在我继续之前显示图像至关重要。

    DoWork(...)
    {
        List<Test> tests = ....
    
        for (Test t in tests)
        {
            switch(t.Name)
            {
                case "Test1":
                    //Do something
                    break;
                case "Test2":
                    //Do something else 
                    break;
                ...
                case "TestSpecial":
                    // Here I want to:
                    // 1. Tell UI to show an image on the screen
                    // 2. Wait for the image to show up
                    // 3. Continue with my test
                    break;
                case "TestN+1":
                    //Do something completly different
                    break;
            }
        }
    }
    

我可以使用Dispatcher.InvokeAsync 或类似的方法来显示图像,但有什么方法可以等待它完成或以其他方式保证图像在继续之前显示?

【问题讨论】:

  • 为什么不使用像 Coded UI 这样的实际 UI 测试框架?
  • 您可以在后台运行所有测试,显示进度并可以取消。这种等待某事的方式不是问题。否则,您必须以某种方式停止测试(完全退出DoWork)并仅在显示图像(事件?)后继续(再次输入)。
  • @ DanielMann 在这种情况下,它不是关于测试 UI,应用程序本身正在使用相机测试硬件。 @Bolu Thx,会调查的。
  • 你怎么知道“图像正在显示”?

标签: c# wpf multithreading backgroundworker


【解决方案1】:

我认为,如果您将 BackgroundWorker 用作此处显示的 http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx 和 ProgressChanged 事件,它会成功。

编辑:这是您的案例中应用的那篇 msdn 文章中的代码

//create worker
BackgroundWorker bw = new BackgroundWorker();

//set progress to true
bw.WorkerReportsProgress = true; 

// handle events
bw.DoWork += new DoWorkEventHandler(DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

//method for work
private DoWork(object sender, DoWorkEventArgs e)
{

BackgroundWorker worker = sender as BackgroundWorker;
List<Test> tests = ....

for (Test t in tests)
{
    switch(t.Name)
    {
        case "Test1":
            //Do something
            break;
        case "Test2":
            //Do something else 
            break;
        ...
        case "TestSpecial":
            // Here I want to:
            // 1. Tell UI to show an image on the screen
            // 2. Wait for the image to show up
            // 3. Continue with my test
            worker.ReportProgress(1);
            break;
        case "TestN+1":
            //Do something completly different
            break;
    }
}
} 

//method for progress
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    //set your image here
}

【讨论】:

  • 请避免链接到其他网站的答案;此类链接意外更改,无法被 SO 搜索使用,并且阅读它的人无法判断它是否真的回答了问题或只是垃圾邮件。至少,提供链接内容的摘要。
  • 抱歉,我编辑了我的帖子。我没有想到这一点。我只是不喜欢复制粘贴,我认为即使提到该事件也应该有所帮助。我宁愿只发表评论,但我不能,因为我没有足够的声誉。
  • ... +1,您按照 Dour 的要求扩展了答案。干得好。
  • @TomKos 可以将图片作为参数System.Drawing.Image
【解决方案2】:

我认为可怜的老 @TomKos 已经找到了答案……如果他能更好地解释自己就好了。

首先,请查看我在 StackOverflow 上的 Progress Bar update from Background worker stalling 帖子中的 BackgroundWorker 类的示例实现。

现在,在DoWork 方法中,请注意对backgroundWorker.ReportProgress(i); 的调用。这会将一个数字传递回 UI 线程,该数字表示已完成工作的百分比。

当您想要显示图像时,您可以实现类似的功能并将特定值传递回 UI。在您的 DoWork 方法的某个阶段,您可以像这样将值传回:

private void DoWork(object sender, DoWorkEventArgs e)
{
    // Do some long running process here
    backgroundWorker.ReportProgress(1); // Send signal to show the image
    // Maybe do some more long running process here
}

您可以在 UI 中像这样处理它:

private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    if (e.ProgressPercentage == 1)
    {
        // Show your image
    }
}

【讨论】:

    【解决方案3】:

    100% 的情况下,从您告诉 UI 显示图像到图像出现在屏幕上,会有一段延迟。游戏玩家在显卡上花很多钱是有原因的。

    Loaded 是最后一个事件。
    Loaded 事件在最终渲染之前引发,但在布局系统计算出所有必要的渲染值之后。

    没有渲染事件(我知道)。

    我会尝试延迟 Loaded 事件。
    100,000 并不多。
    即使是 1/10 秒的延迟也只有几个小时。

    【讨论】:

      猜你喜欢
      • 2010-10-20
      • 1970-01-01
      • 2017-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多