Search code examples
.netwinformsdrop-down-menucontextmenustriphighdpi

Area for check mark in WinForms ContextMenuStrip is narrow on high dpi


We have a WinForms app for .NET Framework 4.7.2. The main form contains a toolbar based on the ToolStrip component. One of the buttons displays a drop-down menu based on the ContextMenuStrip component. The whole construction looks like this:

private ToolStrip MainToolStrip;
private ToolStripDropDownButton TextSizeButton;
private ContextMenuStrip TextSizeMenu;

MainToolStrip = new ToolStrip();
TextSizeButton = new ToolStripDropDownButton();
TextSizeMenu = new ContextMenuStrip();

MainToolStrip.Items.AddRange(new ToolStripItem[] {..., TextSizeButton, ...});

TextSizeButton.DropDown = TextSizeMenu;

High dpi support is enabled in the app using the standard <System.Windows.Forms.ApplicationConfigurationSection> element in the app config file (according to this Microsoft guide).

This drop-down menu looks good on a normal 96dpi screen, but the picture is not so good on a high-res screen because the width of the gray area for check mark is not enough:

enter image description here

How to fix this issue?


Solution

  • To avoid any further incompatibilities and side effects related to the standard implementation of check marks in ContextMenuStrip, we decided to simply use our own image as the check mark:

    enter image description here enter image description here

    It looks even cooler than the default one because the default implementation draws the selection rectangle around the check mark (why?!):

    enter image description here

    The core part of code that switches the check state is the following:

    private Bitmap ImageCheck = CreateToolButtonResBitmap("check.png");
    private Bitmap ImageEmpty = CreateToolButtonResBitmap("10tec-empty.png");
    
    private void SetMenuItemChecked(ToolStripMenuItem item, bool check)
    {
        if (check)
            item.Image = ImageCheck;
        else
            item.Image = ImageEmpty;
    }
    

    And we also remove the unneeded gray area at the left of ContextMenuStrip for better effect:

    internal class DropDownToolbarRenderer : ToolStripProfessionalRenderer
    {
        protected override void OnRenderImageMargin(ToolStripRenderEventArgs e)
        {
        }
    }
    
    private static DropDownToolbarRenderer fDropDownToolbarRenderer = new DropDownToolbarRenderer();
    
    TextSizeMenu.Renderer = fDropDownToolbarRenderer;