views:

1716

answers:

6

I have derived a TabControl with the express purpose of enabling double buffering, except nothing is working as expected. Here is the TabControl code:

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

This Tabcontrol is then set with it's draw mode as 'OwnerDrawnFixed' so i can changed the colours. Here is the custom drawing method:

 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);
  }

 }

All to no avail however, as this control is not double buffered and still flickers when resized.

Any ideas?

A: 

Not sure, but you might try double-buffering the control that contains the tab control.

C. Dragon 76
A: 

I looked around quite a bit, tried your code and whatever else I could think of, but I don't see a way to get rid of the flicker. Unfortunately, in my tests even a regular (non-owner-drawn) tab control flickers during resizing.

For what it's worth, turning off "Show window contents while dragging" will fix it, but I realize that may not be helpful.

Charlie
oh well, thanks for trying.
Gary Willoughby
+1  A: 

If you read the documentation, it says, "This member is not meaningful for this control." If you want the control to be drawn utilizing double-buffering, you'll have to implement it yourself. Besides the fact that if you owner-draw the control, you would have to implement double-buffering yourself anyhow.

Robert C. Barth
A: 

I think it doesn't work because you are disabling double buffering!

All this.DoubleBuffered = true does is set ControlStyles.OptimizedDoubleBuffer to true. Since you are disabling that flag in the next line of your program, you are really doing nothing. Remove ControlStyles.OptimizedDoubleBuffer (and perhaps ControlStyles.AllPaintingInWmPaint) and it should work for you.

alabamasucks
+1  A: 
Peter Crabtree
A: 

I've had problems with double buffering on controls in the past and the only way to stop the flicker was to ensure the inherited OnPaintBackground method was not being called. (See code below) You will also need to ensure the entire backgound is painted during your paint call.

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