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

ProgressBar работает медленно в Windows Forms

Я использую Windows Vista и Visual Studio 2010. Создайте приложение .Net 4 для Windows Forms. Отбросьте индикатор выполнения по умолчанию, добавьте код для обработки события загрузки формы и выполните progressBar1.Value = 100; там.

Начните отладку, и вы увидите анимацию, перемещающую индикатор выполнения до 100 за полсекунды.

Мне нужен 2 бара прогресса в моем проекте. Один из них относится к "глобальному прогрессу", а второй относится к "текущему шагу прогресса", поэтому второй идет от 0 до 100, а курица возвращается к 0 для следующего шага. Проблема заключается в том, что с медленным шагом выполнения для некоторых быстрых шагов он никогда не достигает 100, и это выглядит странно.

Есть ли способ избавиться от этой анимации? В WPF это нормально, но я предпочел бы остаться с Windows Forms.

4b9b3361

Ответ 1

Именно так разработан индикатор прогресса Vista/7. Когда вы изменяете значение индикатора выполнения, панель анимируется до этого значения постепенно.

Единственный способ избежать этой проблемы - вернуться назад при обновлении индикатора выполнения следующим образом:

progressBar1.Value = n;
if (n>0)
    progressBar1.Value = n-1;

Для более полного обсуждения см. Отключение анимации progress progress.NET при изменении значения?

Ответ 2

Создание подсказки Хеффернана в обратном порядке с индикатором выполнения и подход метода расширения Рейнхарта в связанный с этим вопрос, я придумал свое решение.

Решение довольно бесшовно и успешно справляется с проблемой, с которой вы столкнетесь, когда значение находится в Maximum. Этот метод расширения ProgressBar уменьшает отставание, вызванное прогрессивным стилем анимации, присутствующим в элементе управления WinForms ProgressBar при работе в Windows Vista и 7 (я еще не тестировал в Windows 8).

public static class ExtensionMethods
{
    /// <summary>
    /// Sets the progress bar value, without using 'Windows Aero' animation.
    /// This is to work around a known WinForms issue where the progress bar 
    /// is slow to update. 
    /// </summary>
    public static void SetProgressNoAnimation(this ProgressBar pb, int value)
    {
        // To get around the progressive animation, we need to move the 
        // progress bar backwards.
        if (value == pb.Maximum)
        {
            // Special case as value can't be set greater than Maximum.
            pb.Maximum = value + 1;     // Temporarily Increase Maximum
            pb.Value = value + 1;       // Move past
            pb.Maximum = value;         // Reset maximum
        }
        else
        {
            pb.Value = value + 1;       // Move past
        }
        pb.Value = value;               // Move to correct value
    }
}

Использование примера:

private void backgroundWorker_ProgressChanged(object sender, 
                                                  ProgressChangedEventArgs e)
{
     progressBar.SetProgressNoAnimation(e.ProgressPercentage);
}

Ответ 3

Вы можете легко написать пользовательский индикатор выполнения, чтобы показать его значение без анимации. Ниже приведена простая реализация, показывающая прогресс от 0 до 100 и возврат к 0.

public class ProgressBarDirectRender : UserControl
{
    private int _value;
    public int Value
    {
        get { return _value; }
        set
        {
            if (value < 0 || value > 100)
                throw new ArgumentOutOfRangeException("value");
            _value = value;
            const int margin = 1;
            using (var g = CreateGraphics())
            {
                if (_value == 0)
                    ProgressBarRenderer.DrawHorizontalBar(g, ClientRectangle);
                else
                {
                    var rectangle = new Rectangle(ClientRectangle.X + margin,
                                                  ClientRectangle.Y + margin,
                                                  ClientRectangle.Width * _value / 100 - margin * 2,
                                                  ClientRectangle.Height - margin * 2);
                    ProgressBarRenderer.DrawHorizontalChunks(g, rectangle);
                }
            }
        }
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        ProgressBarRenderer.DrawHorizontalBar(e.Graphics, ClientRectangle);
    }
}