ProgressBar работает медленно в Windows Forms
Я использую Windows Vista и Visual Studio 2010. Создайте приложение .Net 4 для Windows Forms. Отбросьте индикатор выполнения по умолчанию, добавьте код для обработки события загрузки формы и выполните progressBar1.Value = 100;
там.
Начните отладку, и вы увидите анимацию, перемещающую индикатор выполнения до 100 за полсекунды.
Мне нужен 2 бара прогресса в моем проекте. Один из них относится к "глобальному прогрессу", а второй относится к "текущему шагу прогресса", поэтому второй идет от 0 до 100, а курица возвращается к 0 для следующего шага. Проблема заключается в том, что с медленным шагом выполнения для некоторых быстрых шагов он никогда не достигает 100, и это выглядит странно.
Есть ли способ избавиться от этой анимации? В WPF это нормально, но я предпочел бы остаться с Windows Forms.
Ответы
Ответ 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);
}
}