ProgressBar在Windows窗体中很慢

我正在使用Windows Vista和Visual Studio 2010.创建.Net 4 Windows窗体应用程序。 删除默认表单上的进度条,添加代码以处理表单加载事件并执行progressBar1.Value = 100; 那里。

开始调试,你会看到动画在大约半秒内将进度条移动到100。

我的项目需要2个进度条。 一个用于“全局进展”,第二个用于“当前步进”,因此第二个从0到100,并且回到0以进行下一步。 问题是,由于某些快速步骤的进度条缓慢,它永远不会达到100并且看起来很奇怪。

有没有办法摆脱那个动画? 在WPF中没关系,但我宁愿继续使用Windows Forms。

这就是Vista / 7进度条的设计方式。 当您更改进度条的值时,该栏会逐渐动画到该值。

我知道避免这个问题的唯一方法是在更新进度条时倒退,如下所示:

 progressBar1.Value = n; if (n>0) progressBar1.Value = n-1; 

有关更完整的讨论,请参阅更改值时禁用.NET进度条动画?

借助进度条和Reinhart的扩展方法在相关问题中向后推进Heffernan的提示 ,我提出了自己的解决方案。

该解决方案非常无缝,并成功处理了值为Maximum时将遇到的问题。 ProgressBar这种扩展方法减轻了在Windows Vista和7上运行时WinForms ProgressBar控件中存在的渐进式动画样式导致的滞后 (我还没有在Windows 8上测试过)。

 public static class ExtensionMethods { ///  /// Sets the progress bar value, without using 'Windows Aero' animation. /// This is to work around a known WinForms issue where the progress bar /// is slow to update. ///  public static void SetProgressNoAnimation(this ProgressBar pb, int value) { // To get around the progressive animation, we need to move the // progress bar backwards. if (value == pb.Maximum) { // Special case as value can't be set greater than Maximum. pb.Maximum = value + 1; // Temporarily Increase Maximum pb.Value = value + 1; // Move past pb.Maximum = value; // Reset maximum } else { pb.Value = value + 1; // Move past } pb.Value = value; // Move to correct value } } 

样品用法:

 private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar.SetProgressNoAnimation(e.ProgressPercentage); } 

您可以轻松编写自定义进度条以显示其值而无需动画。 以下是一个简单的实现,用于显示从0到100的进度并恢复为0。

 public class ProgressBarDirectRender : UserControl { private int _value; public int Value { get { return _value; } set { if (value < 0 || value > 100) throw new ArgumentOutOfRangeException("value"); _value = value; const int margin = 1; using (var g = CreateGraphics()) { if (_value == 0) ProgressBarRenderer.DrawHorizontalBar(g, ClientRectangle); else { var rectangle = new Rectangle(ClientRectangle.X + margin, ClientRectangle.Y + margin, ClientRectangle.Width * _value / 100 - margin * 2, ClientRectangle.Height - margin * 2); ProgressBarRenderer.DrawHorizontalChunks(g, rectangle); } } } } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); ProgressBarRenderer.DrawHorizontalBar(e.Graphics, ClientRectangle); } } 

我喜欢Derek W的答案 ,我设法找到了一个支持数据绑定的解决方案。 我从System.Windows.Forms.ProgressBarinheritance并创建了新的可绑定属性。 否则它是一样的:

 [DefaultBindingProperty("ValueNoAnimation")] public class NoAnimationProgressBar : ProgressBar { ///  /// Sets the progress bar value, without using 'Windows Aero' animation. /// This is to work around (hack) for a known WinForms issue where the progress bar /// is slow to update. ///  public int ValueNoAnimation { get => Value; set { // To get around the progressive animation, we need to move the // progress bar backwards. if (value != Maximum) Value = value + 1; // Move past else { // Special case as value can't be set greater than Maximum. Maximum = value + 1; Value = value + 1; Maximum = value; } Value = value; // Move to correct value } } } 

您可以像这样绑定到属性(viewModel有一个名为Value的int属性):

 var dataSource = new BindingSource { DataSource = _viewModel }; progressBarBindingHack.DataBindings.Add("ValueNoAnimation", dataSource, "Value");