在我向 tabControl1 添加自定义背景色后,我的 tabControl1 不会显示其 DrawImage

My tabControl1 wont show its DrawImage after I added custom backcolor to my tabControl1

我不太确定我哪里出错了,但在我将自定义背景色添加到我的 tabControl1 之前一切正常,我看到其他选项卡上的 X 和添加选项卡的 +

添加此代码源后,我添加的选项卡不存在了,但 + 按钮功能和其他选项卡功能也让我觉得 backColor 只是将它们隐藏在后面。

            SolidBrush backColor = new SolidBrush(Color.FromArgb(40, 40, 40)); // change back color
            e.Graphics.FillRectangle(backColor, rec);

有没有什么方法可以让标签页完全显示我用背景颜色放入的 DrawItem?

代码来源:

        private void tabControl1_DrawItem_1(object sender, DrawItemEventArgs e)
        {
            Rectangle rec = tabControl1.ClientRectangle;

            SolidBrush backColor = new SolidBrush(Color.FromArgb(40, 40, 40)); // change back color
            e.Graphics.FillRectangle(backColor, rec);

            StringFormat StrFormat = new StringFormat();
            StrFormat.LineAlignment = StringAlignment.Center;
            StrFormat.Alignment = StringAlignment.Center;

            Brush bshBack = new SolidBrush(Color.FromArgb(55, 55, 55)); // change tab color

            var tabPage = this.tabControl1.TabPages[e.Index];
            var tabRect = this.tabControl1.GetTabRect(e.Index);
            tabRect.Inflate(-2, -2);
            if (e.Index == this.tabControl1.TabCount - 1)
            {
                // Add
                var addImage = Properties.Resources.Add;
                e.Graphics.FillRectangle(bshBack, e.Bounds);
                e.Graphics.DrawImage(addImage,
                    tabRect.Left + (tabRect.Width - addImage.Width) / 2,
                    tabRect.Top + (tabRect.Height - addImage.Height) / 2);
            }
            else
            {
                // Close
                var closeImage = Properties.Resources.Close;
                e.Graphics.FillRectangle(bshBack, e.Bounds);
                e.Graphics.DrawImage(closeImage,
                    (tabRect.Right - closeImage.Width),
                    tabRect.Top + (tabRect.Height - closeImage.Height) / 2);
                TextRenderer.DrawText(e.Graphics, tabPage.Text, tabPage.Font,
                    tabRect, tabPage.ForeColor, TextFormatFlags.Left);
            }
        }

扩展 解决方案。新建一个class并继承TabControl,在构造函数中设置如下所示的控件样式,主要是按照你想要的方式绘制控件和选项卡。

using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;

namespace YourProjectNamespace
{
    [DesignerCategory("Code")]
    [ToolboxBitmap(typeof(TabControl))]
    public class TabControlEx : TabControl
    {
        public TabControlEx() : base()
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint
                | ControlStyles.ResizeRedraw
                | ControlStyles.OptimizedDoubleBuffer
                | ControlStyles.UserPaint, true);
            UpdateStyles();
            Padding = new Point(14, 4);
        }

        private Color backColor = Color.FromArgb(40, 40, 40);
        /// <inheritdoc cref="Control.BackColor"/>
        [DefaultValue(typeof(Color), "40, 40, 40"),
            Browsable(true),
            EditorBrowsable(EditorBrowsableState.Always),
            DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public new Color BackColor
        {
            get => backColor;
            set
            {
                if (backColor != value)
                {
                    backColor = value;
                    Invalidate();
                }
            }
        }

        private Image addImage;
        [DefaultValue(null)]
        public Image AddButtonImage
        {
            get => addImage;
            set
            {
                addImage = value;
                Invalidate();
            }
        }

        private Image closeImage;
        [DefaultValue(null)]
        public Image CloseButtonImage
        {
            get => closeImage;
            set
            {
                closeImage = value;
                Invalidate();
            }
        }

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            SendMessage(Handle, TCM_SETMINTABWIDTH, IntPtr.Zero, (IntPtr)16);
            if (TabCount > 0) TabPages[TabCount - 1].Text = "";
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            var g = e.Graphics;

            g.Clear(BackColor);

            if (TabCount == 0) return;

            for (int i = 0; i < TabCount; i++)
            {
                var tp = TabPages[i];
                var r = Rectangle.Inflate(GetTabRect(i), -4, 0);

                if (i == TabCount - 1)
                {
                    if (AddButtonImage != null)
                        g.DrawImage(AddButtonImage,
                            r.X + (r.Width - AddButtonImage.Width) / 2,
                            r.Y + (r.Height - AddButtonImage.Height) / 2,
                            AddButtonImage.Width, AddButtonImage.Height);
                }
                else
                {
                    if (i == SelectedIndex)
                        using (var brSel = new SolidBrush(Color.FromArgb(105, 105, 105)))
                            g.FillRectangle(brSel, Rectangle.Inflate(r, 4, 1));

                    if (ImageList != null && tp.ImageIndex >= 0)
                        ImageList.Draw(g, 
                            r.X, r.Y + (r.Height - ImageList.ImageSize.Height) / 2, 
                            tp.ImageIndex);

                    if (CloseButtonImage != null)
                    {
                        var closeRect = new Rectangle(new Point(
                            r.Right - CloseButtonImage.Width,
                            r.Y + (r.Height - CloseButtonImage.Height) / 2),
                            CloseButtonImage.Size);

                        g.DrawImage(CloseButtonImage, closeRect,
                            0, 0, CloseButtonImage.Width, CloseButtonImage.Height,
                            GraphicsUnit.Pixel);
                    }

                    TextRenderer.DrawText(g, tp.Text, tp.Font, r, Color.White,
                        TextFormatFlags.HorizontalCenter | 
                        TextFormatFlags.VerticalCenter);
                }
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            var lastIndex = TabCount - 1;
            if (GetTabRect(lastIndex).Contains(e.Location))
            {
                var args = new AddingTabEventArgs();
                OnAddingTab(args);
                if (args.Cancel) return;

                var newTp = new TabPage
                {
                    Text = "New Tab",
                    BackColor = BackColor
                };
                TabPages.Insert(lastIndex, newTp);
                SelectedIndex = lastIndex;
            }
            else
            {
                for (var i = 0; i < TabPages.Count; i++)
                {
                    var r = Rectangle.Inflate(GetTabRect(i), -4, 0);

                    if (new Rectangle(r.Right - 16, r.Y + (r.Height - 16), 16, 16)
                        .Contains(e.Location))
                    {
                        var args = new ClosingTabEventArgs(TabPages[i]);
                        OnClosingTab(args);
                        if (args.Cancel) return;

                        TabPages[i].Dispose();
                        break;
                    }
                }
            }
        }

        protected override void OnSelecting(TabControlCancelEventArgs e)
        {
            if (e.TabPageIndex == TabCount - 1)
                e.Cancel = true;
            else
                base.OnSelecting(e);
        }

        public event EventHandler<ClosingTabEventArgs> ClosingTab;

        protected virtual void OnClosingTab(ClosingTabEventArgs e) => 
            ClosingTab?.Invoke(this, e);

        public event EventHandler<AddingTabEventArgs> AddingTab;

        protected virtual void OnAddingTab(AddingTabEventArgs e) =>
            AddingTab?.Invoke(this, e);

        const int TCM_SETMINTABWIDTH = 0x1300 + 49;

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    }

    public class ClosingTabEventArgs : EventArgs
    {
        public ClosingTabEventArgs(TabPage tp) => TabPage = tp;

        public TabPage TabPage { get; }

        public bool Cancel { get; set; }
    }

    public class AddingTabEventArgs : EventArgs
    {
        public AddingTabEventArgs() { }

        public bool Cancel { get; set; }
    }
}

请注意,我又添加了两个事件,AddingTabClosingTab 以在您的实施中捕获它们并执行您需要的任何操作,包括取消。

private void tabControlEx1_AddingTab(object sender, AddingTabEventArgs e)
{
    if (MessageBox.Show("Add new TabPage?", "Alert", 
        MessageBoxButtons.YesNo) == DialogResult.No)
        e.Cancel = true;
}

private void tabControlEx1_ClosingTab(object sender, ClosingTabEventArgs e)
{
    if (MessageBox.Show($"Remove {e.TabPage.Text}?", "Alert", 
        MessageBoxButtons.YesNo) == DialogResult.No)
        e.Cancel = true;
}

当然,您可以进一步扩展控件并添加更多绘图属性,例如 back/foreground 普通选项卡和选定选项卡的颜色。另外,您可以尝试 LinearGradientBrush 填充背景而不是实心画笔。

重建,在ToolBoxwindow之上,找到并放下一个实例。尝试返回代码以添加您的风格。