【问题标题】:C# progressBar not updating until half progress completeC# progressBar 直到一半进度完成才更新
【发布时间】:2014-08-25 17:14:12
【问题描述】:

我正在使用dispatcherTimer 来更新进度条的值:

DispatcherTimer tim = new DispatcherTimer();
tim.Interval = TimeSpan.FromMilliseconds(100);
tim.Tick += delegate
{
    if (valuee < max)
    {
        prog.Value = valuee;
    }
    else
    {
        tim.Stop();
    }
};

并像这样设置progressBar的最大值:

using (FileStream fs = File.Open(Filename, FileMode.Open))
{
    if (fs.Length > 10485760 && fs.Length <= 209715200)
        prog.Maximum = fs.Length / 1024;
    else if (fs.Length <= 10485760)
        prog.Maximum = fs.Length / 16;
    else if(fs.Length > 209715200)
        prog.Maximum = fs.Length / 1048576;
}

然后在for循环的每次迭代后增加值:

var Input = File.OpenRead(path);
int Size = MainWindow.prog.Maximum;
for (long i = 0; i < Input.Length; i += Size)
{
    MainWindow.valuee++;
    PasswordEnter.valuee++;
    byte[] chunkData = new byte[chunkSize];
    int bytesRead = 0;
    while ((bytesRead = fsInput.Read(chunkData, 0, chunkSize)) > 0)
    {
        if (bytesRead != chunkSize)
        {
            for (int x = bytesRead - 1; x < chunkSize; x++)
            {
                chunkData[x] = 0;
            }
        }
        cryptoStream.Write(chunkData, 0, bytesRead);
    }
}

编辑:这就是我调用 AESCryptography 类的方式:

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (obj, l) => lo.Encrypt(Filename, password.Password, "main");
worker.RunWorkerAsync();

但由于某种原因,progressBar 直到超过一半的迭代结束才更新!怎么了?

【问题讨论】:

  • 什么代码在哪个线程上运行? for 循环中还会发生什么?
  • block #3 在另一个线程上
  • 您是否有理由避免在BackgroundWorker 线程上使用ReportProgress/ProgressChanged 机制?更新进度条和状态显示对我来说效果很好。您的循环代码打开一个文件,然后在for 循环内递增进度(valuee)。 while 循环似乎读取到文件结尾。然后for 循环继续让while 确保它仍然处于EOF,因为没有打开新文件。 (我假设InputfsInput 应该是同一个变量。)
  • @HABO 发表您的评论作为答案,以便我接受!

标签: c# .net wpf progress-bar dispatchertimer


【解决方案1】:

DispatcherTimer 队列在 Dispatcher 线程上工作,该线程是 WPF UI 线程。

这是 MSDN 关于计时器执行的说法:

DispatcherTimer 在每个 Dispatcher 循环的顶部重新计算。 定时器不能保证在时间间隔发生时准确执行,但它们保证在时间间隔发生之前不会执行。这是因为 DispatcherTimer 操作像其他操作一样放置在 Dispatcher 队列中。 DispatcherTimer 操作何时执行取决于队列中的其他作业及其优先级。

您正在经历进度计时器的滞后,因为您很可能正在运行一个长时间的阻塞操作,该操作拒绝处理不同请求的消息循环。

你有两个选择:

  1. 将长时间运行的操作移至后台线程。我更喜欢这种方法。

  2. 尝试使用DispatcherTimer overload,它采用DispatcherPriority 并指定更高的优先级。这种方法仍然不能保证您会体验到性能上的变化,但它可能会有所帮助。

【讨论】:

  • 你能添加它的代码吗?我想看看你怎么称呼它
  • 完成。格式不正确,但我仍然发布它
  • 我想看到 调用 到后台线程,而不是内部运行的委托
  • 看起来不错。您的 UI 线程中是否还有其他事情发生?
  • 我刚刚注意到:valuee 更新一次,等待很长一段时间然后开始正常工作。但是 for 循环中的其余代码不会停止一次!
【解决方案2】:

您的循环代码打开一个文件,然后在 for 循环内增加进度 (valuee)。 while 循环似乎读取到文件结尾。然后for 循环继续让while 确保它仍然处于EOF,因为没有打开新文件。 (我假设InputfsInput 应该是同一个变量。)

BackgroundWorker 线程上的ReportProgress/ProgressChanged 机制是处理从后台工作线程更新 UI 的跨线程复杂性的可靠方法。您可以使用UserState 传递其他信息,例如当前正在处理以显示在标签中的文件的名称。

【讨论】:

    猜你喜欢
    • 2023-03-05
    • 1970-01-01
    • 2020-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多