Мерцание в приложении Windows Forms

У меня есть приложение с множеством элементов управления. И он очень сильно мерцает, особенно при запуске.

Я применил к нему это исправление.

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x02000000;   // WS_EX_COMPOSITED
            return cp;
        }
    } 

Это отлично сработало - мерцание уменьшилось на невероятную величину. Однако побочным эффектом является то, что кнопки «Свернуть», «Развернуть» и «Закрыть» в правом верхнем углу окна не анимируются, когда я наводю указатель мыши на них или щелкаю по ним (хотя они все еще работают). Это придает приложению ощущение зависания.

Как сохранить WS_EX_COMPOSITED, сохранив при этом удобство использования кнопок «Развернуть», «Свернуть» и «Закрыть»?

Это происходит в Windows XP. Как отметил @fallenidol, в Windows 7 это не проблема.


person AngryHacker    schedule 20.07.2010    source источник
comment
Идеальный вопрос (мне нужна эта функциональность, я пробовал это разрешение, как мне достичь этой функциональности с этим новым ограничением).   -  person Matt Mitchell    schedule 20.07.2010
comment
Кстати, я попробовал это исправление в тестовом приложении, работающем в Windows 7, и кнопки «Развернуть», «Свернуть» и «Закрыть» все еще кажутся анимированными.   -  person pmcilreavy    schedule 21.07.2010
comment
@fallenidol. Это хорошо знать. Все мои клиенты на XP.   -  person AngryHacker    schedule 21.07.2010
comment
Я знаю, что это старый пост, но когда WS_EX_COMPOSITED включен в Win 7 SP1, анимация кнопок «Развернуть», «Свернуть» и «Закрыть» исчезла.   -  person Ignacio    schedule 28.03.2019


Ответы (5)


Я понял. Уловка состоит в том, чтобы удалить флаг WS_EX_COMPOSITED после отображения формы. Полное объяснение и код в моем блоге:

Как избавиться от мерцания в приложениях Windows Forms

person AngryHacker    schedule 21.07.2010
comment
@Hossein: Да, блог пока недоступен ... надеюсь, он будет восстановлен в какой-то момент в этом месяце. - person AngryHacker; 07.08.2016
comment
Привет, @AngryHacker! Я пробовал то, что вы предлагали, и в Win 10 возникли проблемы с мерцанием и формой MDI. В Win 7 анимация кнопок свертывания, восстановления и закрытия все еще не работает. Не могли бы вы дать мне какие-нибудь подсказки по этому поводу? Заранее благодарю! - person Ignacio; 29.03.2019

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

Вот обходной путь, чтобы перестать мерцать, когда пользователь изменяет размер формы, но без нарушения рисования элементов управления, таких как DataGridView, NumericUpDown и т. Д. При условии, что имя вашей формы - «Form1»:

int intOriginalExStyle = -1;
bool bEnableAntiFlicker = true;

public Form1()
{
    ToggleAntiFlicker(false);
    InitializeComponent();
    this.ResizeBegin += new EventHandler(Form1_ResizeBegin);
    this.ResizeEnd += new EventHandler(Form1_ResizeEnd);
}

protected override CreateParams CreateParams
{
    get
    {
        if (intOriginalExStyle == -1)
        {
            intOriginalExStyle = base.CreateParams.ExStyle;
        }
        CreateParams cp = base.CreateParams;

        if (bEnableAntiFlicker)
        {
            cp.ExStyle |= 0x02000000; //WS_EX_COMPOSITED
        }
        else
        {
            cp.ExStyle = intOriginalExStyle;
        }

        return cp;
    }
} 

private void Form1_ResizeBegin(object sender, EventArgs e)
{
    ToggleAntiFlicker(true);
}

private void Form1_ResizeEnd(object sender, EventArgs e)
{
    ToggleAntiFlicker(false);
}

private void ToggleAntiFlicker(bool Enable)
{
    bEnableAntiFlicker = Enable;
    //hacky, but works
    this.MaximizeBox = true;
}
person John Suit    schedule 28.06.2011
comment
Хорошая точка зрения. У меня был этот код в моем приложении, но я забыл добавить его в свою запись в блоге. Обновлю через пару дней. - person AngryHacker; 29.06.2011
comment
Хорошо, но если я применяю это решение, то при изменении размера формы мерцание снова возвращается. Если я просто использую CreateParams, как в вопросе, мерцание исчезнет даже при изменении размера формы. Возможно, я что-то упускаю ... - person Ignacio; 28.03.2019

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

        // Enable double duffering to stop flickering.
        this.SetStyle(ControlStyles.DoubleBuffer, true);
        this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        this.SetStyle(ControlStyles.UserPaint, true);
        this.SetStyle(ControlStyles.SupportsTransparentBackColor, false);
        this.SetStyle(ControlStyles.Opaque, false);
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        this.SetStyle(ControlStyles.ResizeRedraw, true);
person pmcilreavy    schedule 20.07.2010
comment
Весь смысл опубликованного мной кода заключается в том, что вы делаете это один раз, а не для каждого отдельного пользовательского элемента управления (а их сотни + тонна сторонних элементов управления). - person AngryHacker; 20.07.2010
comment
Это еще один вариант для других людей, просматривающих эту страницу, которые могут не иметь доступа ко всему приложению и просто разрабатывают пользовательский элемент управления изолированно. В следующий раз, когда вы будете разрабатывать однопользовательский элемент управления, вы можете использовать приведенный выше фрагмент кода. Тогда вы можете не оказаться в ситуации, когда у вас есть сотни мерцающих элементов управления. - person pmcilreavy; 21.07.2010

Вам следует попробовать стандартное свойство элемента управления Windows Forms, называемое DoubleBuffered. http://msdn.microsoft.com/en-us/library/system.windows.forms.control.doublebuffered.aspx

person Kru    schedule 20.07.2010
comment
Это работает только для каждого элемента управления. В приведенном мной примере двойная буферизация применяется к каждому элементу управления в форме. - person AngryHacker; 20.07.2010
comment
Вы можете использовать отражение в начале приложения, чтобы заполнить это свойство каждого элемента управления. - person Kru; 20.07.2010
comment
Я не могу этого сделать для сторонних элементов управления, которые не раскрывают это свойство. - person AngryHacker; 21.07.2010
comment
Хммм, любой сторонний элемент управления должен быть унаследован от Windows.Forms.Control. Даже если это свойство закрыто, вы также можете использовать отражение для доступа к любому частному или защищенному свойству. - person Kru; 22.07.2010

Я только что наткнулся на этот пост и понял, что он немного староват. Однако у меня такая же проблема с моей формой, и я обнаружил (во всяком случае, для XP) неэлегантное решение, похоже, не включает визуальные стили.

person Tebc    schedule 09.12.2012
comment
Как продолжение, у меня, похоже, нет проблем с мерцанием, когда я переопределяю OnPaintBackground. Если я не хочу, чтобы фон закрашивался, я вызываю e.Graphics.Clear ([соответствующий цвет]) и возвращаюсь, в противном случае вызывается метод базового события. Как я уже сказал, это, кажется, решает проблему. Однако мне интересно, какие могут возникнуть непредвиденные последствия. - person Tebc; 10.12.2012
comment
Исправление. Вышеупомянутое переопределение, похоже, работает, пока для свойства минимального размера формы установлен текущий размер. - person Tebc; 10.12.2012