1

我正在尝试显示一个 WPF 弹出窗口,它将指示一些进展:

问题是在 Thread.Sleep 完成之前没有显示弹出窗口,这只是一个示例,在我的程序中,我有复杂的 IO 和 DB 逻辑需要同步执行,并且需要在弹出窗口上显示进度。

这是我的示例代码:

    private ProgressBar m_ProgressBar;

    private void buttonDoWork_Click(object sender, RoutedEventArgs e)
    {
        var progressPopup = new Popup { PopupAnimation = PopupAnimation.Fade, StaysOpen = true, Height = 150, Width = 260 };
        m_ProgressBar = new ProgressBar
                              {
                                  HorizontalAlignment = HorizontalAlignment.Stretch,
                                  VerticalAlignment = VerticalAlignment.Stretch
                              };

        progressPopup.Child = m_ProgressBar;

        progressPopup.IsOpen = true;

        Thread.Sleep(5000);
        this.m_ProgressBar.Value = 25;
        Thread.Sleep(5000);
        this.m_ProgressBar.Value = 50;
        Thread.Sleep(5000);
        this.m_ProgressBar.Value = 75;
        Thread.Sleep(5000);
        this.m_ProgressBar.Value = 100;
    } 

更新

问题是阻塞主线程的逻辑需要留在主线程上,我无能为力。有没有办法在单独的线程上运行弹出窗口?

4

3 回答 3

4

采用

Dispather.BeginInvoke(new Action(()=>{ this.m_ProgressBar.Value = progress; });

更新 UI 线程上的进度条。

一般来说,你不应该像这样编织你的代码(用户界面和逻辑混在一起)

您可以使用 BackgroundWorker 或通过引发事件来报告进度的任务。

编辑

澄清一下:公开从您的 ViewModel/代码更改的数据并引发事件 (PropertyChanged),以便您可以将 UI 绑定到这些值。这将允许您保持 UI 和代码分离。

于 2012-05-22T13:27:36.350 回答
0

我会BackgroundWorker在 UI 线程和后台线程的拆分非常清晰的地方使用。

例如,使用它,您可以签署ProgressChanged事件(属于 UI 线程)并执行任何您想要告知用户您的后台进程的事情。

于 2012-05-22T13:41:34.930 回答
0

问题是 WPF 要求消息循环旋转,以便它可以调度消息以显示、绘制、响应事件等。您必须构建代码以便buttonDoWork_Click尽快退出。如果你不这样做,那么整个 UI 将冻结。

此外,在该单一方法中增加进度值基本上没有任何作用。从消息循环的角度来看,进度值仅包含一个值...100。ProgressBar这是您在单击事件结束之前写入的最后一个值。这是进度条知道的唯一值,当它最终被允许刷新时。

您需要从 UI 线程中获取长时间运行的操作。这是我的建议。

  • 使用Task该类在工作线程上开始您的操作。
  • 让您的工作线程将进度信息发布到一个简单的变量。
  • 让您的 UI 线程在您选择的时间间隔内通过计时器轮询进度信息。相应地更新ProgressBar
于 2012-05-22T14:00:17.997 回答