Во время прокрутки FlowLayoutPanel фон искажается + мерцает

У меня есть приложение формы Windows, которое имеет фон. Внутри у меня есть панель управления потоком с прозрачным фоном. Когда я прокручиваю, происходит следующее:

введите здесь описание изображения

Я также вижу некоторое мерцание. Я перепробовал весь бизнес с двойной буферизацией, и он не работает.

Какие-либо предложения?


person Andy Hin    schedule 27.07.2010    source источник


Ответы (5)


Да, это не работает. Вот класс, который несколько улучшает его:

using System;
using System.Windows.Forms;

class MyFlowLayoutPanel : FlowLayoutPanel {
    public MyFlowLayoutPanel() {
        this.DoubleBuffered = true;
    }
    protected override void OnScroll(ScrollEventArgs se) {
        this.Invalidate();
        base.OnScroll(se);
    }
}

Скомпилируйте и перетащите его из верхней части панели инструментов на форму. Однако это не может решить фундаментальную проблему, параметр «Показывать содержимое окна при перетаскивании». Это системная опция, она будет включена в более поздних версиях Windows. Когда он включен, Windows сама прокручивает содержимое панели, а затем просит приложение нарисовать ту часть, которая была открыта прокруткой. Метод OnScroll переопределяет это, обеспечивая перерисовку всего окна, чтобы фоновое изображение оставалось на месте. Конечный результат не очень хорош, вы увидите, как изображение делает «пого», прыгая вверх и вниз во время прокрутки.

Единственное решение для этого — отключить системную опцию. Это не практическое решение, пользователям нравится этот вариант, и он влияет на все программы, а не только на вашу. Если вы не можете жить с пого, вам придется отказаться от прозрачности.

person Hans Passant    schedule 27.07.2010

это то, что сработало для меня.

public class CustomFlowLayoutPanel : FlowLayoutPanel
{
    public CustomFlowLayoutPanel()
        : base()
    {
        this.SetStyle(ControlStyles.UserPaint, true);
        this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
    }

    protected override void OnScroll(ScrollEventArgs se)
    {
        this.Invalidate();

        base.OnScroll(se);
    }
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x02000000; // WS_CLIPCHILDREN
            return cp;
        }
    }
}
person MajinFro    schedule 24.05.2012
comment
Я сделал это, и это сработало нормально, но я также заставил его перерисовывать при изменении размера, потому что по какой-то причине это не очень умно делать это само по себе. - person Camilo Martin; 15.02.2013
comment
Отлично, работает для меня. Не могли бы вы уточнить, что на самом деле делает этот CreateParams, и как вы его нашли? Вы сами об этом узнали? - person Mike de Klerk; 12.02.2014

Я очень рад сообщить, что Ганс и Интернет в целом (просто изучите WPF.... пфффф) ошибаются.

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

Так как же решить эту проблему?

  1. Установите прокручиваемый элемент управления на DoubleBuffered.

  2. Перехватывайте сообщения WM_HSCROLL/WM_VSCROLL. Недействительный. Установите для флага «do_not_paint» значение true. Вызовите base.WndProc(). Установите для флага «do_not_paint» значение false. Обновлять.

  3. Перехватите WM_PAINT и связанные с ним сообщения. Вызывайте base.WndProc() только в том случае, если флаг «do_not_paint» имеет значение false.

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

person Ryan Killian    schedule 05.12.2011

Я добавил Application.DoEvents() к событию Scroll панели FlowPanel и остановил размытие дочерних элементов управления FlowPanel, которые я получал.

person user3165730    schedule 27.04.2014
comment
Это самое простое и простое решение. Спасибо! - person Topher Birth; 13.07.2017
comment
Application.DoEvents может прервать логику вашей программы, поэтому его не следует использовать так просто. Вместо этого займитесь реальной проблемой! - person tmighty; 20.12.2020
comment
Да, я бы не стал использовать Application.DoEvents. Это может испортить элементы flowlayoutpanel, когда у вас наверняка много элементов. - person Eldhose; 13.02.2021

Это немного поздно ... но это случается, если вы возитесь с Color.Transparent. Проверьте, имеет ли ваш FlowLayoutPanel прозрачный фон. Если это так, попробуйте изменить это.

person André Fiedler    schedule 08.08.2013