Проблема двойной буферизации производного отрисованного владельцем TabControl?

StackOverflow https://stackoverflow.com/questions/223628

Вопрос

Я получил TabControl с целью включить двойную буферизацию, за исключением того, что ничего не работает должным образом. Вот код TabControl:

class DoubleBufferedTabControl : TabControl
{
    public DoubleBufferedTabControl() : base()
    {
        this.DoubleBuffered = true;
        this.SetStyle
            (
                ControlStyles.UserPaint |
                ControlStyles.AllPaintingInWmPaint |
                ControlStyles.ResizeRedraw |
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.SupportsTransparentBackColor,
                false
            );
    }
}

Затем этот Tabcontrol устанавливается с режимом рисования как OwnerDrawnFixed, поэтому я могу менять цвета. Вот пользовательский метод рисования:

    private void Navigation_PageContent_DrawItem(object sender, DrawItemEventArgs e)
    {
        //Structure.
        Graphics g = e.Graphics;
        TabControl t = (TabControl)sender;
        TabPage CurrentPage = t.TabPages[e.Index];

        //Get the current tab
        Rectangle CurrentTabRect = t.GetTabRect(e.Index);

        //Get the last tab.
        Rectangle LastTab = t.GetTabRect(t.TabPages.Count - 1);

        //Main background rectangle.
        Rectangle BackgroundRect = new Rectangle(LastTab.Width, t.Bounds.Y - 4, t.Width - (LastTab.Width), t.Height);

        //Tab background rectangle.
        Rectangle TabBackgroundRect = new Rectangle(0, LastTab.Y + LastTab.Height, LastTab.Width, t.Bounds.Height - (LastTab.Y + LastTab.Height));

        //Set anitialiasing for the text.
        e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

        //String format for the text.
        StringFormat StringFormat = new StringFormat();
        StringFormat.Alignment = StringAlignment.Center;
        StringFormat.LineAlignment = StringAlignment.Center;

        //Fill the background.
        g.FillRectangle(Brushes.LightGray, BackgroundRect);
        g.FillRectangle(Brushes.Bisque, TabBackgroundRect);

        //Draw the selected tab.
        if(e.State == DrawItemState.Selected)
        {
            g.FillRectangle(Brushes.White, e.Bounds);
            Rectangle SelectedTabOutline = new Rectangle(e.Bounds.X + 2, e.Bounds.Y + 2, e.Bounds.Width, e.Bounds.Height - 4);
            g.DrawRectangle(new Pen(Brushes.LightGray, 4f), SelectedTabOutline);
            g.DrawString(CurrentPage.Text, new Font("Arial", 12f, FontStyle.Bold, GraphicsUnit.Point), new SolidBrush(Color.FromArgb(70, 70, 70)), CurrentTabRect, StringFormat);
        }
        else
        {
            g.FillRectangle(new SolidBrush(Color.FromArgb(230, 230, 230)), e.Bounds);
            g.DrawString(CurrentPage.Text, new Font("Arial", 12f, FontStyle.Regular, GraphicsUnit.Point), Brushes.Gray, CurrentTabRect, StringFormat);
        }

    }

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

Есть идеи?

Это было полезно?

Решение

Если вы читаете документацию, там написано: «Этот элемент не имеет смысла для этого элемента управления». Если вы хотите, чтобы элемент управления отображался с использованием двойной буферизации, вам придется реализовать его самостоятельно. Помимо того факта, что если вы используете владелец-элемент управления, вам все равно придется реализовать двойную буферизацию.

Другие советы

Прежде всего, вы можете избавиться от своего TabControl code & # 8212; вы включаете буферизацию, а затем немедленно выключаете ее, так что на самом деле она ничего полезного не делает.

Часть вашей проблемы заключается в том, что вы пытаетесь нарисовать только часть из TabControl .

Самое простое решение, которое дает решение на 90% (все еще возможно получить мерцание), это добавить это в свой класс формы:

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

Если вы хотите очень быть уверенным в отсутствии мерцания, вам нужно нарисовать весь TabControl самостоятельно и не обращать внимания на запросы рисования фона.

Изменить. Обратите внимание, что это будет работать только в XP и более поздних версиях.

В прошлом у меня были проблемы с двойной буферизацией элементов управления, и единственный способ остановить мерцание состоял в том, чтобы гарантировать, что унаследованный метод OnPaintBackground не вызывался. (См. Код ниже). Вам также необходимо убедиться, что весь фон закрашен во время вызова.

protected override void OnPaintBackground( PaintEventArgs pevent )
{
    //do not call base - I don't want the background re-painted!
}

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

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

Для чего стоит отключить " показывать содержимое окна при перетаскивании " Я исправлю это, но я понимаю, что это может быть бесполезно.

Я думаю, что это не работает, потому что вы отключили двойную буферизацию!

Все, что делает this.DoubleBuffered = true , для ControlStyles.OptimizedDoubleBuffer установлено значение true. Поскольку вы отключаете этот флаг в следующей строке вашей программы, вы действительно ничего не делаете. Удалите ControlStyles.OptimizedDoubleBuffer (и, возможно, ControlStyles.AllPaintingInWmPaint), и он должен работать для вас.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top