Is there a way to change the background colour of a tab control in winforms, so that it does not have the white border around it?
I have tried a few different ways, but they all result in the same white bord开发者_C百科er being displayed.
TabControl
has very poor support for customization. I've used this custom tab control with good success. The code is pretty usable if you want to change the look as I did.
I can only think of changing Appearance property to Buttons
MSDN TabControl Appearance
First of all you need to make a deriving class from TabControl. So far so good but now it gets dirty.
Because TabControl won't call OnPaint
, we have do override WndProc
to handle the WM_PAINT message. In there we go ahead and paint our background with the color we like.
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if(m.Msg == (int) WindowsMessages.Win32Messages.WM_PAINT)
{
using (Graphics g = this.CreateGraphics())
{
//Double buffering stuff...
BufferedGraphicsContext currentContext;
BufferedGraphics myBuffer;
currentContext = BufferedGraphicsManager.Current;
myBuffer = currentContext.Allocate(g,
this.ClientRectangle);
Rectangle r = ClientRectangle;
//Painting background
if(Enabled)
myBuffer.Graphics.FillRectangle(new SolidBrush(_backColor), r);
else
myBuffer.Graphics.FillRectangle(Brushes.LightGray, r);
//Painting border
r.Height = this.DisplayRectangle.Height +1; //Using display rectangle hight because it excludes the tab headers already
r.Y = this.DisplayRectangle.Y - 1; //Same for Y coordinate
r.Width -= 5;
r.X += 1;
if(Enabled)
myBuffer.Graphics.DrawRectangle(new Pen(Color.FromArgb(255, 133, 158, 191), 1), r);
else
myBuffer.Graphics.DrawRectangle(Pens.DarkGray, r);
myBuffer.Render();
myBuffer.Dispose();
//Actual painting of items after Background was painted
foreach (int index in ItemArgs.Keys)
{
CustomDrawItem(ItemArgs[index]);
}
}
}
}
Im doing further drawing in this method so it looks a little overkill for this problem but just ignore the unnecessary stuff.
Also notice the foreach
loop. I'll come to this later.
The Problem is that TabControl
paints its items (the tab headers) before its own WM_PAINT so our background will be drawn on top, which renders them invisible. To solve this I made an EventHandler
for DrawItem
which looks as the following:
private void DrawItemHandler(object sender, DrawItemEventArgs e)
{
//Save information about item in dictionary but dont do actual drawing
if (!ItemArgs.ContainsKey(e.Index))
ItemArgs.Add(e.Index, e);
else
ItemArgs[e.Index] = e;
}
I am saving the DrawItemEventArgs
into a dictionary (which is called "ItemArgs" in my case) so I can access them later. Thats where the foreach
from a few seconds ago comes into play. It calls a method where I am painting the tab headers which takes the DrawItemEventArgs
which we saved before as a parameter to paint the items in correct state and position.
So, in a nutshell we are intercepting the Drawing of tab headers to delay it until we are finished drawing the background.
This solution is not optimal but it works and its the only thing you can do to get more control over TabControl
(lol) without painting it from scratch.
Easier still (IMO): add a paint handler to the TabPage (not the top level TabControl, but the TabPage(s) within it, then paint the background rectangle in the color you want.
Either in the designer or "by hand", add a Paint event handler to the TabPage:
Page1.Paint += tabpage_Paint; // custom paint event so we get the backcolor we want
In the paint method, paint the page rectangle the color you want (in my case, I want it to follow the standard BackColor):
// force the tab background to the current BackColor private void tabpage_Paint(object sender, PaintEventArgs e) { SolidBrush fillBrush = new SolidBrush(BackColor); e.Graphics.FillRectangle(fillBrush, e.ClipRectangle); }
Drop a Panel on top of (not inside) the tab control and set the color in the properties. Call Panelx.Hide() and Panelx.Show() as needed.
Unfortunately, the back color property is handled when the control is drawn. My suggestion is to do what I have done and create a user control to mimic the tab controller.
I used a menu strip as the tabs and had a second user control docked as fill to the parent user control. In the second user control, I was able to add whatever I needed for said tab.
The part that is harder with it is that you have to build all the functionality to make it work as a tab control.
精彩评论