Search code examples
c#toolstrip

c# winforms toolstripmenuitem change color disabled state item


When a ToolStripItem is disabled, among other UI changes is that it's Text and Image is greyed out and changes to ForeColor are ignored.

I need to override one the event responsible for painting the toolstrip items.

i use my own custom toolstrip but I don't see the solution to integrate it.

I would like to be able to change the ForeColor Text and Image even when Enabled = false.

    public class MyMenuRenderer : ToolStripRenderer
    {

        protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
        {
            base.OnRenderMenuItemBackground(e);

            if (e.Item.Enabled)
            {
                if (e.Item.IsOnDropDown == false && e.Item.Selected)
                {
                    var rect = new Rectangle(0, 0, e.Item.Width - 1, e.Item.Height - 1);
                    var rect2 = new Rectangle(0, 0, e.Item.Width - 1, e.Item.Height - 1);
                    e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(17, 23, 43)), rect);
                    e.Graphics.DrawRectangle(new Pen(new SolidBrush(Color.Black)), rect2);
                    e.Item.ForeColor = Color.White;
                }
                else
                {
                    e.Item.ForeColor = Color.White;

                }

                if (e.Item.IsOnDropDown && e.Item.Selected)
                {
                    var rect = new Rectangle(0, 0, e.Item.Width - 1, e.Item.Height - 1);
                    e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(47, 50, 65)), rect);
                    e.Graphics.DrawRectangle(new Pen(new SolidBrush(Color.Black)), rect);
                    e.Item.ForeColor = Color.White;
                }
                if ((e.Item as ToolStripMenuItem).DropDown.Visible && e.Item.IsOnDropDown == false)
                {
                    var rect = new Rectangle(0, 0, e.Item.Width - 1, e.Item.Height - 1);
                    var rect2 = new Rectangle(0, 0, e.Item.Width - 1, e.Item.Height - 1);
                    e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(8, 11, 26)), rect);
                    e.Graphics.DrawRectangle(new Pen(new SolidBrush(Color.Black)), rect2);
                    e.Item.ForeColor = Color.White;
                }
            }
        }
        protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
        {
            base.OnRenderSeparator(e);
            var DarkLine = new SolidBrush(Color.Black);
            var rect = new Rectangle(30, 3, e.Item.Width - 30, 1);
            e.Graphics.FillRectangle(DarkLine, rect);
        }

        protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e)
        {
            base.OnRenderItemCheck(e);

            if (e.Item.Selected)
            {
                var rect = new Rectangle(4, 2, 16, 16);
                var rect2 = new Rectangle(5, 3, 14, 14);
                SolidBrush b = new SolidBrush(Color.FromArgb(8, 11, 26));
                SolidBrush b2 = new SolidBrush(Color.FromArgb(67, 139, 242));

                e.Graphics.FillRectangle(b, rect);
                e.Graphics.FillRectangle(b2, rect2);
                e.Graphics.DrawImage(e.Image, new Point(4, 3));
            }
            else
            {
                var rect = new Rectangle(4, 2, 16, 16);
                var rect2 = new Rectangle(5, 3, 14, 14);
                SolidBrush b = new SolidBrush(Color.FromArgb(8, 11, 26));
                //SolidBrush b2 = new SolidBrush(Color.FromArgb(20, 115, 177));
                SolidBrush b2 = new SolidBrush(Color.FromArgb(67, 139, 242));

                e.Graphics.FillRectangle(b, rect);
                e.Graphics.FillRectangle(b2, rect2);
                e.Graphics.DrawImage(e.Image, new Point(4, 3));
            }
        }

        protected override void OnRenderImageMargin(ToolStripRenderEventArgs e)
        {
            base.OnRenderImageMargin(e);

            var rect = new Rectangle(0, 0, e.ToolStrip.Width, e.ToolStrip.Height);
            e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(8, 11, 26)), rect);

            var DarkLine = new SolidBrush(Color.FromArgb(8, 11, 26));
            var rect3 = new Rectangle(0, 0, 26, e.AffectedBounds.Height);
            e.Graphics.FillRectangle(DarkLine, rect3);

            e.Graphics.DrawLine(new Pen(new SolidBrush(Color.FromArgb(8, 11, 26))), 28, 0, 28, e.AffectedBounds.Height);

            var rect2 = new Rectangle(0, 0, e.ToolStrip.Width - 1, e.ToolStrip.Height - 1);
            e.Graphics.DrawRectangle(new Pen(new SolidBrush(Color.Black)), rect2);
        }
    }

Solution

  • The strips are nested-multipart controls, each of which is being painted by a dedicated method and can be handled by a dedicated event. So, no such one method/event is responsible for drawing the whole thing. You already have overridden some methods in your code snippet.

    To override the default style of the disabled items, you need to override the OnRenderItemText and OnRenderItemImage methods to prevent calling the base methods and draw the parts as you like. I'll derive the renderer here from the ToolStripProfessionalRenderer derived class instead to use a custom ProfessionalColorTable in order to reduce the rendering code. You'll get the same result by just overriding the relevant properties.

    The ColorTable

    As I understand your code snippet:

    public class MyColorTable : ProfessionalColorTable
    {
        public override Color MenuStripGradientBegin => Color.FromArgb(8, 11, 26);
        public override Color MenuStripGradientEnd => Color.FromArgb(8, 11, 26);
        public override Color ToolStripDropDownBackground => Color.FromArgb(8, 11, 26);
        public override Color ImageMarginGradientBegin => Color.FromArgb(8, 11, 26);
        public override Color ImageMarginGradientMiddle => Color.FromArgb(8, 11, 26);
        public override Color ImageMarginGradientEnd => Color.FromArgb(8, 11, 26);
        public override Color MenuItemPressedGradientBegin => Color.FromArgb(8, 11, 26);
        public override Color MenuItemPressedGradientMiddle => Color.FromArgb(8, 11, 26);
        public override Color MenuItemPressedGradientEnd => Color.FromArgb(8, 11, 26);
        public override Color MenuBorder => Color.Black;
        public override Color MenuItemBorder => Color.Empty;
        public override Color SeparatorDark => Color.Black;
        public override Color CheckBackground => Color.Empty;
        public override Color CheckPressedBackground => Color.Empty;
        public override Color CheckSelectedBackground => Color.Empty;
        public override Color ButtonSelectedBorder => Color.Empty; 
    }
    

    See the other virtual properties.

    The Renderer

    public class MyMenuRenderer : ToolStripProfessionalRenderer
    {
    
        private MyMenuRenderer() : base() { }
    
        public MyMenuRenderer(MyColorTable colorTable) : base(colorTable) 
            => RoundedEdges = false;
    
        protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
        {
            if (e.Item.Enabled)
            {
                if (e.Item.IsOnDropDown)
                {
                    if (e.Item.Selected)
                    {
                        var rect = new Rectangle(0, 0, e.Item.Width, e.Item.Height - 1);
    
                        using (var br = new SolidBrush(Color.FromArgb(47, 50, 65)))
                            e.Graphics.FillRectangle(br, rect);
                        e.Graphics.DrawRectangle(Pens.Black, rect);
    
                        return;
                    }
                }
                else if (e.Item.Selected && !e.Item.Pressed)
                {
                    var rect = new Rectangle(0, 0, e.Item.Width - 1, e.Item.Height - 1);
                    var rect2 = new Rectangle(0, 0, e.Item.Width - 1, e.Item.Height - 1);
                    using (var br = new SolidBrush(Color.FromArgb(17, 23, 43)))
                        e.Graphics.FillRectangle(br, rect);
                    e.Graphics.DrawRectangle(Pens.Black, rect2);
    
                    return;
                }
            }
    
            base.OnRenderMenuItemBackground(e);
        }
    
        protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e)
        {
            // I got this...
            // base.OnRenderItemCheck(e);
    
            var rect = e.ImageRectangle;
            var rect2 = Rectangle.Inflate(rect, -1, -1);
    
            using (SolidBrush b = new SolidBrush(Color.FromArgb(8, 11, 26)))
            using (SolidBrush b2 = new SolidBrush(Color.FromArgb(67, 139, 242)))
            {
                e.Graphics.FillRectangle(b, rect);
                e.Graphics.FillRectangle(b2, rect2);
                e.Graphics.DrawImage(e.Image, rect);
            }
        }
    
        protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
        {
            // I got this...
            // base.OnRenderItemText(e);
    
            if (e.Item.Enabled)
            {
                if (e.TextColor == SystemColors.MenuText ||
                    e.TextColor == SystemColors.HighlightText ||
                    e.TextColor == SystemColors.ControlText)
                    e.TextColor = Color.White;
            }
            else
            {
                e.TextColor = Color.LightCoral;
            }
    
            TextRenderer.DrawText(
                e.Graphics, 
                e.Text, 
                e.TextFont, 
                e.TextRectangle, 
                e.TextColor,
                e.TextFormat);
        }
    
        protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
        {
            e.ArrowColor = e.Item.Enabled ? Color.White : Color.LightCoral;
            base.OnRenderArrow(e);
        }
    
        protected override void OnRenderItemImage(ToolStripItemImageRenderEventArgs e)
        {
            // I got this...
            // base.OnRenderItemImage(e);
    
            e.Graphics.DrawImage(e.Image, e.ImageRectangle);
        }
    }
    

    See the other methods and events.

    Use the Renderer

    menuStrip1.Renderer = new MyMenuRenderer(new MyColorTable());