【问题标题】:Progress bar value is not synchronized with what gets rendered in windows 7进度条值与 Windows 7 中呈现的内容不同步
【发布时间】:2011-09-18 17:00:47
【问题描述】:

似乎在 Windows 7 中,设置进度条的值时会发生一些动画。设置值似乎并没有等待动画完成。有没有办法通知进度条何时完成动画?

我有一个示例程序。请看cmets。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Threading;

namespace Testing
{
   static class Program
   {
      [STAThread]
      static void Main()
      {
         Application.EnableVisualStyles();
         Application.SetCompatibleTextRenderingDefault(false);
         var form = new Form1();
         form.Run();
      }
   }

   public partial class Form1 : Form
   {
      public Form1()
      {
         InitializeComponent();
      }

      public void Run()
      {
         Thread thread = new Thread
         (
            delegate()
            {
               ProgressBarMax = 10;
               ProgressValue = 0;

               for (int i = 0; i < 10; i++)
               {
                  Thread.Sleep(1000);
                  ProgressValue++;
               }
            }
         );
         EventHandler show = delegate
         {
            thread.Start();
         };

         Shown += show;
         ShowDialog();
         Shown -= show;
      }

      public int ProgressBarMax
      {
         set
         {
            Invoke
            (
               (MethodInvoker)
               delegate
               {
                  progressBar1.Maximum = value;
               }
            );
         }
      }

      public int ProgressValue
      {
         get
         {
            return progressBar1.Value;
         }
         set
         {
            Invoke
            (
               (MethodInvoker)
               delegate
               {
                  label1.Text = value.ToString();
                  progressBar1.Value = value;

                  // setting the value is not blocking until the
                  // animation is completed. it seems to queue
                  // the animation and as a result a sleep of 1 second
                  // will cause the animation to sync up with the UI
                  // thread.

                  // Thread.Sleep(1000); // this works but is an ugly hack

                  // i need to know if there is a callback to notify me
                  // when the progress bar has finished animating.
                  // then i can wait until that callback is handled 
                  // before continuing.

                  // if not, do i just create my own progress bar?
               }
            );
         }
      }
   }
}

我的 google kung foo 今天好像死了。谢谢。

【问题讨论】:

  • 我只想让进度条的值与其他 ui 组件同步。有 10 步,到第 10 步时,进度显示为 90% 而不是 100%。
  • 为什么要调用 form.Run 而不是 Application.Run(new Form1());在主要方法中?如果你按照你正在做的那样做,事情就不会以同样的方式工作......据我了解,Application.Run 必须由 Windows 窗体应用程序调用,总是 !!
  • to davide:这是一个显示问题的示例应用程序。 run 方法可以很容易地放在程序类中。我并不真正关心 Application.Run;我知道更好。问题是在设置progressBar1.Value = value; 之后,进度条会呈现一段时间。
  • 致 gertarnold:我通常不关心收到有关进度条功能的通知,但是,Windows 7 在不同的线程上渲染得很糟糕。我有两个选择:1)实现我自己的进度条——这很荒谬,或者 2)找出一个简单的机制来等待进度条完成渲染更新的值。微软做了一些傻事不是我的错,但我现在必须处理它。

标签: c# winforms progress-bar


【解决方案1】:

最后这和C# progress bar not synced with download (WebClient class)是同一个问题。

此问题也类似于ProgressBar is slow in Windows Forms。这里的解决方案是前后移动值,即progressBar1.Value = value + 1; progressBar1.Value = value;。第一次更新开始动画序列,而第二次更新强制动画序列提前停止。这是一个很好的解决方法,但可能会引入难以重现的问题。似乎没有真正的解决方案。

最后,Disabling progress bar animation on Vista Aero 建议关闭主题。这似乎可行,但进度条失去了它的外观和感觉。最终,最好的办法就是制作我自己的进度条。

微软应该只是让动画成为一种选择,而不是强迫开发者重新发明进度条。

【讨论】:

  • 这可行,但不适用于最终更改为 100%,因为设置值高于 maxvalue 会导致超出范围异常。愚蠢的是,有一个 MarqueeAnimationSpeed 设置正是为了指定更新延迟,但它似乎对此没有任何影响。
  • 我找到了最后一个值的解决方法:将进度条的最大值设置为最大值 + 1,然后将该值设置为相同的最大值,然后将最大值设置回其原始最大值。这将在栏处于 100% 时触发立即更新
【解决方案2】:

这对我有用:

if (progressBar1.Value <= progressBar1.Maximum - 2)
{
    progressBar1.Value += 2;
    progressBar1.Value--;
}                    
else if (progressBar1.Value <= progressBar1.Maximum)
{                    
    progressBar1.Maximum--;                   
}   

它会很快更新进度条,并在最后一步将其更新为 100%。希望它可以帮助某人。

【讨论】:

  • 调整 MAX——有一定意义——可能是内部渲染器重新调整了彩条而不是触发动画。但是,我不知道为什么 +=2 和 -- 实际上可以解决问题,但至少在 Windows10 上确实如此。这真是太疯狂了。
  • 我明白了。妈的,我明白了。使用 +=2 -=1 技巧,当进度条的状态减少时不做动画。可怕的动画仅在增加值时应用。减小的值会立即重新渲染,没有延迟。
  • 这肯定是愚蠢的修复,但它有效!!!真的很感激。谢谢。这也适用于 VB.NET。
【解决方案3】:

感谢 LuisG 的回答,我注意到 ProgressBar 中的“填充动画”仅在实际增加值时应用。减小该值时,不使用动画并立即更新栏。

这允许我们在不使用多个条件的情况下利用它 - 我们只需要确保设置我们期望值的最后一个值更新是减少值的行为:

var tmp = progress.Maximum;
progress.Maximum = int.MaxValue;
progress.Value = int.MaxValue;
progress.Value = desiredValue;
progress.Maximum = tmp;

上述技巧有效,因为增加 MAX 和 VALUE 会触发动画,因此不会立即渲染。然后我们立即减小该值,这会省略(尚未执行的)动画并呈现新状态。巧合的是,这正是我们最初想要的状态。

仅当desiredValue 小于int.MaxValue 时,上述技巧才有效。如果您想要完整的整数范围,您必须使用 LuisG 的技巧来检测 100% 的最终情况并执行 Maximum-- 而不是提高值。

【讨论】:

    猜你喜欢
    • 2010-11-18
    • 2019-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多