进度条值与 Windows 7 中渲染的内容不同步

发布于 2024-12-05 08:19:06 字数 2544 浏览 2 评论 0原文

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

我有一个示例程序。请看评论。

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?
               }
            );
         }
      }
   }
}

我的谷歌功夫今天似乎死了。谢谢。

It seems that in windows 7, there is some animation that takes place when setting a progress bar's value. Setting the value does not seem to wait for the animation to complete. Is there a way to be notified of when the progress bar has finished animating?

I have a sample program. Please see the comments.

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?
               }
            );
         }
      }
   }
}

My google kung foo seems to be dead today. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

沧笙踏歌 2024-12-12 08:19:06

最后,这与 C# 进度条未同步是相同的问题带有下载(WebClient 类)

此外,此问题类似于 Windows 窗体中的进度条速度缓慢。这里的解决方案是向前和向后移动值,即progressBar1.Value = value + 1; ProgressBar1.Value = 值;。第一次更新开始动画序列,而第二次更新则强制动画序列提前停止。这是一个很好的修复,但可能会带来难以重现的问题。似乎没有真正的解决方案。

最后,在 Vista Aero 上禁用进度条动画建议关闭主题。这似乎有效,但进度条失去了它的外观和感觉。最终,最好的办法就是制作我自己的进度条。

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

In the end this is the same issue as C# progress bar not synced with download (WebClient class).

Also this issue is similar to ProgressBar is slow in Windows Forms. The solution here is to move the value forward and back, i.e. progressBar1.Value = value + 1; progressBar1.Value = value;. The first update begins the animation sequence, while the second update forces the animation sequence to stop early. Its a good fix but can introduce problems that are hard to reproduce. It just doesn't seem like there is a real solution.

Finally, Disabling progress bar animation on Vista Aero suggests to turn off themes. This seems to work, but the progress bar loses its look and feel. Ultimately, the best thing to do is just make my own progress bar.

Microsoft should just make the animation an option instead of forcing developers to re-invent the progress bar.

临走之时 2024-12-12 08:19:06

这对我来说很有效:

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

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

This did the trick for me:

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

It updates the progress bar pretty quick and takes care of the last step to update it to 100%. Hope it helps someone.

北陌 2024-12-12 08:19:06

感谢 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-- 而不是提高值。

Thanks to LuisG's answer, I noticed that the "filling animation" in ProgressBar is applied only on when actually increasing the value. When decreasing the value the animation is not used and the bar is updated instantly.

This allows us to exploit it without using several conditions - we just need to ensure that the last Value update that sets our desired value is an act of decreasing the Value:

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

Above trick works because increasing the MAX and VALUE triggers the animation, so it is NOT rendered instantly. Immediately then we decrease the value, and that omits the (not yet performed) animation and renders new state. Coincidentally, that's the state we wanted in the first place.

Above trick works only if desiredValue is less than int.MaxValue. If you want full integer range, you must use LuisG's trick with detecting the final case of 100% and doing Maximum-- instead of raising the Value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文