8

我有一个 ProgressBarWindow,上面有一个进度条和一个取消按钮,用于报告文件 I/O 的进度。但是,ProgressBarWindow 的 UI 线程和我的主窗口都挂起,尽管所有工作都是在后台工作人员中完成的。渲染进度条,就像我的主窗口一样,但在后台工作人员执行其操作时不会更新。在主窗口的构造函数的最后调用以下代码:

iCountLogLinesProgressBar = new ProgressBarWindow();
iCountLogLinesProgressBar.cancelButton.Click += EventCountLogLinesProgressBarCancelButtonClicked;
iCountLogLinesProgressBar.Show();

iCountLogRecords = new BackgroundWorker();
iCountLogRecords.DoWork += EventCountLogLinesDoWork;
iCountLogRecords.ProgressChanged += EventCountLogLinesProgressChanged;
iCountLogRecords.RunWorkerCompleted += EventCountLogLinesRunWorkerCompleted;
iCountLogRecords.WorkerReportsProgress = true;
iCountLogRecords.WorkerSupportsCancellation = true;
iCountLogRecords.RunWorkerAsync(new BinaryReader(File.Open(iMainLogFilename, FileMode.Open, FileAccess.Read)));

EventCountLogLinesProgressChanged() 看起来像这样:

private void EventCountLogLinesProgressChanged(object sender, ProgressChangedEventArgs e)
{
    iCountLogLinesProgressBar.Value = e.ProgressPercentage;
}

这是 ProgressBarWindow 的简化版本(剩下的只是几个 setter):

public partial class ProgressBarWindow : Window
{
    public ProgressBarWindow()
    {
        InitializeComponent();
        this.progressBar.Value = this.progressBar.Minimum = 0;
        this.progressBar.Maximum = 100;
    }

    public double Value
    {
        get
        {
            return progressBar.Value;
        }
        set
        {
            this.progressBar.Value = value;
        }
    }
} 

我尝试将 value setter 行包装在 dispatcher.invoke 委托中,但这给了我一个堆栈溢出(我不应该有一个 dispatcher.invoke 行,因为 backgroundworker 在 UI 线程中调用 ProgressChanged,对吧?)。我检查了 msdn 并用谷歌搜索,但我似乎找不到其他人有这个问题。

编辑道歉,我没有意识到我的简化代码阻止了 UI 线程,尽管使用了后台工作程序,但我得到了完全相同的行为,所以我错误地认为它们是等价的。我应该提到我正在使用后台工作人员:P

4

2 回答 2

15

您正在阻塞 UI 线程,因此在循环完成之前它不会重新渲染 UI。

将后台处理移到单独的线程中,并使用适当的Dispatcher调用(或BackgroundWorker)将 UI 更新调用编组回 UI 线程。

如果您的进度条真的只是一个计时器,您可以使用其中一个Timer类来更新它。

编辑:好的,现在您已经更改了代码,对我来说看起来没问题。它应该是线程安全的,因为您只是在 UI 线程上更改 UI。您的后台工作人员是否肯定会定期报告进度?

于 2010-08-02T11:03:33.767 回答
3

听听 Jon Skeet,或者您有时可以调用 Application.DoEvents() 在同一个线程中进行所有 UI 更新。

于 2010-08-02T11:04:56.573 回答