2011-03-16 90 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