Отключение анимации .NET прогрессбар при изменении значения? - PullRequest
21 голосов
/ 17 марта 2011

Я понимаю, что в SO есть и другие вопросы, касающиеся анимации и индикаторов выполнения, но они, похоже, вращаются вокруг избавления от анимации, отображаемой поверх индикатора выполнения, т.е.выделение, которое перемещается по нему.

Я хочу избавиться от анимации, которая используется, когда я устанавливаю новое значение индикатора выполнения.У меня сейчас проблема в том, что выполняемое действие завершается, а затем индикатор выполнения продолжает увеличиваться до своего максимального положения после действия завершено.

Другими словами, если яустановите для свойства Value индикатора выполнения значение 50, я хочу, чтобы оно сразу же переместилось на полпути (если макс. 100), а не медленно переводите индикатор выполнения в это положение, как сейчас.

Если естьна самом деле вопрос о SO, который уже имеет дело с этим, просто закройте как дубликат, и я с радостью удалю его, но я не смог его найти.

Это тот, который я нашел: Отключение анимации WinForms ProgressBar, и он имеет дело с анимацией подсветки, и я не об этом говорю.

Вот простая 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, тема Glass, так что да, держу пари, это относится только к 7 или, возможно, также Vista.

Вот GIF-анимация, которая показываетTПроблема, проект сверху.Вы можете видеть, что, как только кнопка становится активной, через 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; }));

Ответы [ 5 ]

31 голосов
/ 17 марта 2011

Эта анимация функция была введена в Vista с темой Aero.

Однако существует обходной путь.Если вы перемещаете прогресс назад, анимация не отображается.Поэтому, если вы хотите, чтобы он мгновенно увеличился на 50, увеличьте значение на 51, а затем немедленно уменьшите на 1.

Вы вступите в конфликт, когда приблизитесь к 100%, потому что вы не можете установить значение на 101при условии, что максимум установлен на 100).Вместо этого установите Максимум на 1000, скажем, увеличьте до 1000, уменьшите до 999, а затем вернитесь к 1000.

В любом случае, это немного странно, но дает преимущество, которое дает желаемый эффект!

15 голосов
/ 08 июня 2012

Вот мой метод расширения, основанный на рекомендации Дэвида Хеффернана :

Заверни это, скрой его из виду и сделай вид, что его там нет!

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)
    {
        // Don't redraw if nothing is changing.
        if (value == pb.Value)
            return;

        // 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 голосов
/ 08 декабря 2011

Существует еще один способ пропустить анимацию индикатора выполнения в стиле Vista: просто SetState() для элемента управления установите значение PBST_PAUSED, затем установите значение и, наконец, установите его обратно на PBST_NORMAL.

0 голосов
/ 08 января 2019

Теперь следует VB.Net 2.0 и более поздняя версия метода Джонатана Рейнхартса SetProgressNoAnimation. Я надеюсь, что это поможет другим разработчикам VB. Функция setProgressBarValue практически полностью защищена от сбоев. Аппаратный сбой может привести к поломке.

''' <summary>
''' In VB.Net, the value of a progress bar can be set without animation.
''' Set the minimum and the maximum value beforehand.
''' This VB version has been written by EAHMK (Evert Kuijpers) in Tilburg in The Netherlands.
''' See SetProgressNoAnimation in
''' /5523303/otklychenie-animatsii-net-progressbar-pri-izmenenii-znacheniya
''' by Jonathan Reinhart, based on the suggestion of David Heffernan.
''' </summary>
''' <param name="progressBar">
''' The progress bar that is to present the new value.
''' </param>
''' <param name="newValue">
''' The new value to present in the progress bar.
''' </param>
Public Function setProgressBarValue(progressBar As ProgressBar,
                                    newValue As Integer) As Exception
  Try
    ' Extremes are not supported.
    If newValue < progressBar.Minimum _
     Or newValue > progressBar.Maximum _
     Or progressBar.Maximum = progressBar.Minimum _
     Or progressBar.Maximum = Integer.MaxValue Then
      Return New ArgumentException("The value " & CStr(newValue) & " for" _
                & " the progress bar '" & progressBar.Name & "' is out of bounds.")
    End If

    ' By field maximumReached also progress bar value progressBar.Maximum is supported.
    Dim maximumReached As Boolean = newValue = progressBar.Maximum
    If maximumReached Then
      progressBar.Maximum += 1
    End If
    progressBar.Value = newValue + 1

    progressBar.Value = newValue
    If maximumReached Then
      progressBar.Maximum -= 1
    End If
    ' The value has been presented succesfully in the progress bar progressBar.
    Return Nothing
  Catch ex As Exception
    ' Returns an exception but does not crash on it.
    Return ex
  End Try
End Function
0 голосов
/ 15 декабря 2015

Мое абсолютное решение этой проблемы в 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...