Собственный элемент управления WinForms мерцает и имеет плохую производительность

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

  1. Он мерцает, если перерисовывается с помощью метода .NET 'Refresh'.
  2. Плохая производительность.

Элемент управления состоит из трех растровых изображений:

  • Статическое фоновое изображение.
  • Вращающийся ротор.
  • Другое изображение в зависимости от угла ротора.

Все используемые растровые изображения имеют разрешение 500x500 пикселей. Управление работает так: https://www.dropbox.com/s/t92gucestwdkx8z/StatorAndRotor.gif(это gif-анимация)

Пользовательский элемент управления должен отрисовываться каждый раз, когда он получает новый угол ротора. Поэтому у него есть общедоступное свойство RotorAngle, которое выглядит следующим образом:

public double RotorAngle
{
    get { return mRotorAngle; }
    set
    {
        mRotorAngle = value;
        Refresh();
    }
}

Refreshвызывает событие Paint. Обработчик события OnPaintвыглядит следующим образом:

private void StatorAndRotor2_Paint(object sender, PaintEventArgs e)
{
    // Draw the three bitmaps using a rotation matrix to rotate the rotor bitmap.
    Draw((float)mRotorAngle);
}

Но когда я использую этот код, который хорошо работает в других собственных пользовательских элементах управления, пользовательский элемент управления вообще не рисуется, если элемент управления имеет двойную буферизацию через SetStyle(ControlStyles.OptimizedDoubleBuffer, true). Если я не установлю для этого флага значение true, элемент управления мерцает при перерисовке.

В конструкторе элемента управления я установил:

SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.ContainerControl, false);
// User control is not drawn if "OptimizedDoubleBuffer" is true.
// SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.SupportsTransparentBackColor, true);

Сначала я подумал, что он мерцает, потому что фон очищается каждый раз, когда элемент управления рисуется. Поэтому я установил SetStyle(ControlStyles.AllPaintingInWmPaint, true). Но это не помогло.

Итак, почему он мерцает? Другие элементы управления работают очень хорошо с этой настройкой. И почему элемент управления не рисуется, если SetStyle(ControlStyles.OptimizedDoubleBuffer, true).

Я обнаружил, что элемент управления не мерцает, если я вызываю метод Drawсразу после изменения свойства RotorAngle:

public float RotorAngle
{
    get { return mRotorAngle; }
    set
    {
        mRotorAngle = value;
        Draw(mRotorAngle);
    }
}

Но это приводит к очень плохой производительности, особенно в полноэкранном режиме. Невозможно обновлять элемент управления каждые 20 миллисекунд. Вы можете попробовать сами. Ниже я прикреплю полное решение Visual Studio 2008.

Итак, почему такое плохое выступление? Не проблема обновлять другие (собственные) элементы управления каждые 20 миллисекунд. Это действительно только из-за растровых изображений?

Я создал простое визуальное решение Visual Studio 2008, чтобы продемонстрировать две проблемы: https://www.dropbox.com/s/mckmgysjxm0o9e0/WinFormsControlsTest.zip(289,3 КБ)

В каталоге bin\Debugнаходится исполняемый файл.

Спасибо за помощь.

6
задан John Arlen 14 May 2012 в 15:44
поделиться