Подтвердить что ты не робот

Отключение анимации прогресса проекта .NET при изменении значения?

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

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

Другими словами, если я установил свойство 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-анимация, которая показывает проблему, проект сверху. Вы можете видеть, что как только кнопка будет включена, через 1 секунду после того, как была установлена ​​отметка полумесяца, панель прогресса будет анимировать до 100% после того, как кнопка станет включена.

Как вы можете видеть выше, установка кнопки назад для включения и настройка панели прогресса на 100 выполняется "одновременно". В принципе, я не хочу прогрессивного наращивания progressbar, я хочу, чтобы он прыгал прямо на 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; }));
4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

Заверните это, скройте это из вида, и притворяйтесь, что это не там!

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

Ответ 3

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

Ответ 4

Теперь следует 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
''' https://stackoverflow.com/questions/5332616/disabling-net-progressbar-animation-when-changing-value/5332770
''' 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

Ответ 5

Мое абсолютное решение этой проблемы в 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