Search code examples
c#.netwinformsiconsmdi

Scaling the icon used by a maximised MDI child in the parent form's MenuStrip


In an MDI application, when the MDI child form is maximised the icon for the form is used as the context menu icon, displayed on the left of the parent form's MenuStrip. When I set the icon of a form used in an MDI application to something larger than 16x16 (I'm using 32x32) the icon is drawn unscaled, and the menu is resized to suit. Note that if the ICO file also contains a 16x16 version of the icon it works fine.

The following creates a basic application that shows the behaviour:

  • create a new solution and WinForms project
  • change Form1's IsMdiContainer to true
  • add a MenuStrip to Form1
  • create a new form, call it MdiChildForm
  • set MdiChildForm's icon to a 32x32 ICO file, here's one I prepared earlier
  • in Form1 add a menu item, double-click it to create the Click event handler and add the following:

    var child = new MdiChildForm();
    child.MdiParent = this;
    child.Show();
    child.WindowState = FormWindowState.Maximized;
    
  • build and run, click the menu item

Note that when you click the menu item again the icon changes to the default one, this is described in this question and isn't the issue here.

I'm pretty sure this would be described as 'by design' but it is annoying nonetheless. Is there a way to force the context menu icon to scale down, sort of resizing the source icon? I'll probably do that as well, but I'm after some kind of in-code catch-all.


Solution

  • Inspired by @Jeremy Thompson's answer I found a possible workaround. I take the oversized icon, draw it to a new 16x16 bitmap, create a new icon from that, and assign it back to the child form. The new icon needs to be assigned prior to showing the form.

    This code is barely tested, and probably buggy and leaky, and I am not an expert on GDI so beware it may break stuff:

    var bmp = new Bitmap(16, 16);
    using (var g = Graphics.FromImage(bmp))
    {
        g.DrawImage(child.Icon.ToBitmap(), new Rectangle(0, 0, 16, 16));
    }
    var newIcon = Icon.FromHandle(bmp.GetHicon());
    child.Icon = newIcon;
    // ...
    child.Show();