C# 如何在Winforms中更改选项卡控件的背景颜色?

C# 如何在Winforms中更改选项卡控件的背景颜色?,c#,winforms,C#,Winforms,有没有办法在winforms中更改选项卡控件的背景颜色,使其周围没有白色边框 我尝试了几种不同的方法,但它们都会显示相同的白色边框。我只能考虑将外观属性更改为按钮 TabControl对定制的支持非常差。我成功地使用了它。如果您想像我一样更改外观,那么代码非常有用。更简单(IMO):向TabPage(不是顶级TabControl,而是其中的TabPage)添加绘制处理程序,然后以您想要的颜色绘制背景矩形 在设计器或“手动”中,向选项卡页添加绘制事件处理程序: Page1.Paint += tab

有没有办法在winforms中更改选项卡控件的背景颜色,使其周围没有白色边框


我尝试了几种不同的方法,但它们都会显示相同的白色边框。

我只能考虑将外观属性更改为按钮


TabControl
对定制的支持非常差。我成功地使用了它。如果您想像我一样更改外观,那么代码非常有用。

更简单(IMO):向TabPage(不是顶级TabControl,而是其中的TabPage)添加绘制处理程序,然后以您想要的颜色绘制背景矩形

  • 在设计器或“手动”中,向选项卡页添加绘制事件处理程序:

    Page1.Paint += tabpage_Paint; // custom paint event so we get the backcolor we want
    
  • 在paint方法中,将页面矩形绘制为所需的颜色(在我的示例中,我希望它遵循标准背景色):


  • 首先,您需要从TabControl生成一个派生类。到目前为止还不错,但现在它变脏了

    因为TabControl不会调用
    OnPaint
    ,所以我们必须重写
    WndProc
    来处理WM_PAINT消息。在这里,我们继续用我们喜欢的颜色绘制背景

     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]);
                    }
    
                }
            }    
        }
    
    我正在用这个方法做进一步的绘制,所以这个问题看起来有点过分,只是忽略了不必要的东西。 还请注意
    foreach
    循环。我稍后将讨论这个问题

    问题是
    TabControl
    在它自己的WM_绘制之前绘制它的项目(选项卡标题),因此我们的背景将绘制在顶部,从而使它们不可见。为了解决这个问题,我为
    DrawItem
    制作了一个
    EventHandler
    ,如下所示:

        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;
        }
    
    我正在将
    DrawItemEventArgs
    保存到一个字典中(在我的例子中称为“ItemArgs”)因此,我可以稍后访问它们。这就是几秒钟前的
    foreach
    开始发挥作用的地方。它调用了一个方法,在该方法中,我正在绘制选项卡标题,它将
    DrawItemEventArgs
    作为参数保存,以在正确的状态和位置绘制项目

    因此,简而言之,我们正在拦截选项卡标题的绘制,以将其延迟到完成背景绘制为止

    此解决方案不是最佳解决方案,但它可以工作,而且这是您唯一可以做的事情,您可以在不从头开始绘制的情况下对选项卡控件进行更多控制。

    在选项卡控件顶部(而不是内部)放置一个面板,并在属性中设置颜色。
    根据需要调用Panelx.Hide()和Panelx.Show()。

    我认为这并不能解决Tom需要更改边缘和顶部选项卡本身(即标题)颜色的问题TabPress自身的客户端区域如您所描述的那样改变,也可以通过设计器中的TabPab.BuffCuy来完成。使用RHAPSODY的CODEPROTER链接,也可以检查LauraM对其局限性的回答:最后,也考虑这个线程:这只会改变标签项的背景而不是头的背景!没有CRE的好解决方案!创建一个新控件并使用BufferedGraphic我注意到在使用此控件时出现了一个问题。当选项卡比选项卡控件宽,因此这两个箭头出现时,所有内容都会分离。我建议避免这种情况。实现这一点的唯一方法是绘制选项卡控件本身。在CodeProject.com上,您可以获得主题颜色。您可以关闭控件的视觉样式,但这会使其返回到战舰灰色,仍然无法更改。
        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;
        }