【问题标题】:Making a progress bar update in real time in wpf在wpf中实时更新进度条
【发布时间】:2015-04-26 01:26:35
【问题描述】:

我无法让进度条实时显示更新。

这是我现在的代码

for (int i = 0; i < 100; i++)
{
     progressbar1.Value = i;
     Thread.Sleep(100);
}

但由于某种原因,当函数运行时进度条显示为空,然后在函数完成运行之前什么也没有。有人可以向我解释如何做到这一点吗?我是 C#/WPF 的新手,所以我不能 100% 确定如何在不同的线程上实现 Dispatcher(如其他一些帖子所示)来解决这个问题。

为了澄清,我的程序有一个按钮,当按下它时,它会从文本框中获取值,并使用 API 来检索信息,并基于它创建标签。我希望在每行数据处理完毕后更新进度条。

这就是我现在拥有的:

private async void search(object sender, RoutedEventArgs e)
{
    var progress = new Progress<int>(value => progressbar1.Value = value);
    await Task.Run(() =>
    {
        this.Dispatcher.Invoke((Action)(() =>
        {
             some pre-processing before the actual for loop occur
             for (int i = 0; i < numberofRows; i++)
             {
                  label creation + adding
                  ((IProgress<int>)progress).Report(i);
             }
        }));
    });
}

谢谢!

【问题讨论】:

  • stackoverflow.com/a/22085142/906773 基本上就是您所需要的。如果你在实现它时遇到问题,你能展示更多你的实际代码吗?
  • 摆脱 Dispatcher.Invoke - 你所做的只是阻塞整个操作的 UI 线程。进度应该处理同步。
  • 问题是当函数尝试执行时没有 Dispatcher.Invoke,就会出现这种情况。 “调用线程无法访问此对象,因为不同的线程拥有它。”当函数尝试访问文本框内的内容时会发生这种情况。
  • 在哪一行?你在那里做其他 UI 工作吗?仅在与 UI 相关的部分上添加 Dispatcher.Invoke。
  • 是的,我正在创建标签,并将其添加到主网格中。这也使用了一些外部 API 工具来获取信息,这些信息会进入标签内容。

标签: c# wpf wpf-controls


【解决方案1】:

如果您使用的是 .NET 4.5 或更高版本,则可以使用async/await

var progress = new Progress<int>(value => progressBar.Value = value);
await Task.Run(() =>
{
    for (int i = 0; i < 100; i++)
    {
        ((IProgress<int>)progress).Report(i);
        Thread.Sleep(100);
    }
});

您需要使用async 关键字标记您的方法才能使用await,例如:

private async void Button_Click(object sender, RoutedEventArgs e)

【讨论】:

  • 问题是我的按钮点击循环 X 次,我希望每次循环后,进度条都会更新:\你能帮我实现这个吗?
  • @nonion 我不太明白你需要什么,但原理很简单:将所有耗时的工作放在await Task.Run(() =&gt; { } 块中(一个方法中可能有多个这样的块)。并在您想更新进度条时输入((IProgress&lt;int&gt;)progress).Report(i);。你可以在Report参数中放入任何整数值而不是i,它将是进度条的新值。
  • 哦,好的,非常感谢您的帮助。我尝试使用已实现的代码编译代码,但出现此错误:调用线程无法访问此对象,因为不同的线程拥有它。这是我尝试更改网格内的标签的时候。
  • 找到了解决方法。 (stackoverflow.com/questions/9732709/…) 使程序编译,但现在我遇到的问题是发生了同样的事情,即栏不会自动更新
  • @nonion 如果没有实际代码,很难说哪里出了问题。请使用您的新代码更新您的帖子。
【解决方案2】:

设法使它工作。我需要做的就是不要让它只是

progressBar1.value = i;

我不得不这样做

progressbar1.Dispatcher.Invoke(() => progressbar1.Value = i, DispatcherPriority.Background);

【讨论】:

  • 相反,你需要移除调用`this.Dispatcher.Invoke((Action)(() =>. By using Task.Run`你是在 background 线程中并要求在 UI 线程中执行工作函数。难怪进度条无法更新。在这个答案中,您将进度条更新移动到后台线程,从而使错误更加复杂。
  • @PanagiotisKanavos 介意分享您的解决方案吗?
  • @IamDOM 事实上,这个答案是双重错误的——它不仅使用了一种过时的技术,而且它代替了一个好的解决方案。该问题已使用Progress&lt; T&gt;,因此代码已在 .NET 4.5 中运行,
【解决方案3】:

您应该使用 .NET 中包含的BackgroundWorker,它为您提供了报告事件中后台线程进度的方法。创建 BackGroundWorker 的线程会自动调用该事件。

BackgroundWorker.ProgressChanged 可用于向用户报告异步操作的进度。

// This event handler updates the progress bar. 
private void backgroundWorker1_ProgressChanged(object sender,
    ProgressChangedEventArgs e)
{
    this.progressBar1.Value = e.ProgressPercentage;
}

有关使用此功能的更多信息,请参阅 MSDN。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多