2011-03-16 91 views
20

我意识到有关于动画和进度条的其他问题,但它们似乎围绕着摆脱进度条顶部绘制的动画,即。它的亮点在于它。更改值时禁用.NET progressbar动画?

我想要做的是摆脱当我设置进度栏的新值时使用的动画。我现在遇到的问题是正在运行的操作完成,然后进度条继续增加,直到操作完成后,它的最大位置为

换句话说,如果我将进度条的Value属性设置为50,我希望它立即到达中间位置(如果max为100),不会像现在那样缓慢地建立进度条到该位置。

如果确实存在一个关于SO的问题,已经处理了这个问题,只需重复一次即可,我很乐意将其删除,但我找不到任何问题。

这是我找到的那个:Disabling WinForms ProgressBar animation,它处理的是动画的亮点,这不是我说的。

下面是一个简单LINQPad演示,显示问题:

void Main() 
{ 
    using (var fm = new Form()) 
    { 
     var bt = new Button 
     { 
      Text = "Start", 
      Location = new Point(8, 8), 
      Parent = fm, 
     }; 
     var pb = new ProgressBar 
     { 
      Top = bt.Top + bt.Height + 8, 
      Width = fm.ClientRectangle.Width - 16, 
      Left = 8, 
      Parent = fm 
     }; 

     bt.Click += (s, e) => 
     { 
      bt.Enabled = false; 
      Thread t = new Thread(new ThreadStart(() => 
      { 
       Thread.Sleep(1000); 
       bt.BeginInvoke(new Action(() => { pb.Value = 50; })); 
       Thread.Sleep(1000); 
       bt.BeginInvoke(new Action(() => { pb.Value = 100; })); 
       bt.BeginInvoke(new Action(() => { bt.Enabled = true; })); 
      })); 
      t.Start(); 
     }; 
     fm.ShowDialog(); 
    } 
} 

编辑1:这是Windows 7中,玻璃的主题,所以是的,我敢肯定,这是特定于7或者也可能Vista系统。

下面是一个GIF动画,显示问题,从上面的项目。您可以看到,只要启用该按钮,中途标记设置后1秒,进度条动画高达100%,该按钮已启用。

正如您在上面看到的,将按钮设置为启用并将进度条设置为100会“同时”完成。基本上,我不希望逐步积累进度条,我希望它在启用按钮的同时直接跳到50%,然后再跳到100%。

LINQPad demo


编辑2:针对大卫赫弗南的答案,这是我改变了上面的代码:

bt.BeginInvoke(new Action(() => { pb.Value = 51; pb.Value = 50; })); 
Thread.Sleep(1000); 
bt.BeginInvoke(new Action(() => { pb.Maximum = 101; pb.Value = 101; 
            pb.Maximum = 100; pb.Value = 100; })); 
+0

这立即转到一半标志;没有建立起来。在XP上;可能是操作系统特定的你在Vista/7上? – 2011-03-16 22:35:25

+0

这是Windows 7,64位,让我编辑问题并发布示例视频。此外,感谢您添加该标签:) – 2011-03-16 22:45:49

+0

这很有趣,我偶然发现这个问题,认为我的代码有一段延迟,因为动画实际启动需要大约100ms。 – 2011-09-01 05:48:18

回答

30

这个动画功能在Vista中引入了航空主题。

虽然有一个解决方法。如果您向后移动进度,则不会显示动画。所以如果你想让它立即前进50,那么将值增加51,然后立即减少1.

当你接近100%时,你会陷入冲突,因为你不能将值设置为101(我假设最大值被设置为100)。相反,将最大值设置为1000,比如说增加到1000,减少到999,然后再移回到1000.

无论如何,这有点奇怪,但它确实能够带来理想效果!

+1

好的,我可以忍受,我想:) – 2011-03-16 22:49:15

+1

@Lasse把它包起来,把它隐藏起来,然后假装它不在那里! – 2011-03-16 22:49:46

+1

我在我的问题底部修改了LINQPad代码。你是这个意思吗?它确实如上所述地工作,只是让我感觉有点恶心,但是,假装它不在那里:) – 2011-03-16 22:52:16

2

还有另一种方式来跳过Vista风格进度条的动画: 只是SetState()控制到PBST_PAUSED,然后设定值,并最终将其设置回PBST_NORMAL

+0

你能提供一个如何完成的例子吗? ProgressBar似乎没有SetState()方法。 – Daniel 2016-02-18 13:21:03

+1

这个答案是错误的。 SetState()不存在。我想你是在谈论SendMessage(PBM_SETSTATE,...),但这不会影响进度条的动画。 – Elmue 2016-06-18 03:51:40

14

这里是我的扩展方法的基础上,David Heffernanrecommendation

把它包起来,从视图中隐藏它,假装它不存在!

public static class ExtensionMethods 
{ 
    /// <summary> 
    /// Sets the progress bar value, without using Windows Aero animation 
    /// </summary> 
    public static void SetProgressNoAnimation(this ProgressBar pb, int value) 
    { 
     // To get around this animation, we need to move the progress bar backwards. 
     if (value == pb.Maximum) { 
      // Special case (can't set value > Maximum). 
      pb.Value = value;   // Set the value 
      pb.Value = value - 1;  // Move it backwards 
     } 
     else { 
      pb.Value = value + 1;  // Move past 
     } 
     pb.Value = value;    // Move to correct value 
    } 
} 
+2

没有爱吗?这是一个很好的建议。 – nathanchere 2013-12-12 00:30:54

+0

我喜欢扩展方法解决方案的想法,但是这并没有完全为我处理特殊的边界案例。 – 2014-04-08 14:56:06

+0

使用你的方法作为灵感,我想出了这个,它完成了预期的效果:http://stackoverflow.com/questions/6071626/progressbar-is-slow-in-windows-forms/22941217#22941217 – 2014-04-08 15:23:44

-3

我在VB中这个问题绝对的解决方案...

Sub FileSaving() 

    With barProgress 
     .Minimum = 0 
     .Maximum = 100000000 
     .Value = 100000 
    End With 

    For 
     ... 
     saving_codes 
     ... 
     With barProgress 
      .Maximum = .Value * (TotalFilesCount/SavedFilesCount) 
     End With 
    Next 

End Sub 
+2

这并没有解决被问到的问题。 – 2016-01-22 12:13:49