Desativando a animação da barra de progresso do .NET ao alterar o valor?

Eu percebo que existem outras questões sobre o SO relacionadas a animações e barras de progresso, mas elas parecem girar em torno de se livrar da animação desenhada no topo da barra de progresso, ie. o destaque que passa por cima.

O que eu quero fazer é se livrar da animação que é usada quando eu definir o novo valor da barra de progresso. O problema que tenho agora é que a ação que está sendo executada é concluída e, em seguida, a barra de progresso continua a aumentar até a posição máxima após a conclusão da ação.

Em outras palavras, se eu definir a propriedade Value da barra de progresso como 50, quero que ela se desloque até a posição intermediária (se max for 100) imediatamente, não lentamente crie a barra de progresso para essa posição como faz agora.

Se realmente houver uma pergunta no SO que já lida com isso, feche como duplicado e eu o excluirei felizmente, mas não consegui encontrar nenhum.

Este é o que eu encontrei: Desativando a animação WinForms ProgressBar , e lida com o destaque que é animado, e não é disso que estou falando.

Aqui está uma demonstração simples do LINQPad que mostra o problema:

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

Edit 1: Este é o Windows 7, tema de vidro, então sim, eu aposto que isso é específico para 7 ou possivelmente também Vista.

Aqui está uma animação GIF que mostra o problema, o projeto de cima. Você pode ver que, assim que o botão for ativado, 1 segundo após a marca da metade ter sido definida, a barra de progresso será animada em até 100% após o botão ser ativado.

Como você pode ver acima, definir o botão de volta para habilitado e definir a barra de progresso como 100 é feito “ao mesmo tempo”. Basicamente, eu não quero o acúmulo progressivo da barra de progresso, eu quero que ela pule diretamente para 50% e depois para 100% ao mesmo tempo em que o botão se torna habilitado.

Demonstração do LINQPad


Edit 2: Em resposta à resposta de David Heffernan, foi assim que mudei o código acima:

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

Este recurso de animação foi introduzido no Vista com o tema Aero.

Existe uma solução alternativa embora. Se você mover o progresso para trás, a animação não será mostrada. Portanto, se você quiser avançar 50 vezes instantaneamente, aumente o valor em 51 e diminua imediatamente em 1.

Você entra em conflito quando está perto de 100% porque não pode definir o valor como 101 (suponho que Máximo esteja definido como 100). Em vez disso, configure Máximo para 1000, digamos, aumente para 1000, diminua para 999 e, em seguida, volte para 1000.

De qualquer forma, é meio estranho, mas tem o benefício de lhe dar o efeito desejado!

Aqui está o meu método de extensão, baseado na recomendação de David Heffernan :

Enrole-o, esconda-o de vista e finja que não está lá!

 public static class ExtensionMethods { ///  /// Sets the progress bar value, without using Windows Aero animation ///  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 } } 

Existe outra maneira de pular a animação de uma barra de progresso no estilo Vista: Just SetState() o controle para PBST_PAUSED , então configure o valor e finalmente configure-o de volta para PBST_NORMAL .

Minha solução absoluta para este problema no 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