c# winforms toolstripmenuitem change color disabled state item

336 Views Asked by At

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

There are 2 best solutions below

0
dr.null On BEST ANSWER

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());
1
Laurent On

To change the grey Image in Enabled=false i found a solution with color matrix :

 protected override void OnRenderItemImage(ToolStripItemImageRenderEventArgs e)
    {
        if (!e.Item.Enabled)
        {
            ImageAttributes imageAttributes = new ImageAttributes();
            int width = e.Image.Width;
            int height = e.Image.Height;

            float[][] colorMatrixElements = {
            new float[] { 0.09f,  0,  0,  0, 0},      // Red
            new float[] {0, 0.12f,  0,  0, 0},        // Green
            new float[] {0,  0, 0.22f,  0, 0},        // Blue
            new float[] {0,  0,  0, 1, 0},            // Alpha
            new float[] { 0.1f, 0.1f, 0.17f, 0, 1}};  

            ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);
            imageAttributes.SetColorMatrix(colorMatrix,ColorMatrixFlag.Default,ColorAdjustType.Bitmap);

            e.Graphics.DrawImage(e.Image,e.ImageRectangle,0, 0,width,height,GraphicsUnit.Pixel,imageAttributes);
        }
        else
        {
            base.OnRenderItemImage(e);
        }
    }

To calcul RGBA in matrix i found this : http://andresgalante.com/RGBAtoFeColorMatrix/