How to add an icon to System.Windows.Forms.MenuItem?

雨燕双飞 提交于 2019-12-19 03:38:10

问题


I tried to add an icon to one of my context menu items, but I couldn't do it. Can anybody help me?

Here's the code I've written:

 private System.Windows.Forms.ContextMenu notifyContextMenu;
 private void foo() {
            if (notifyIcon == null) {
                notifyIcon = new System.Windows.Forms.NotifyIcon();   
            }

           if (notifyContextMenu == null) {
               notifyContextMenu = new System.Windows.Forms.ContextMenu();
               notifyContextMenu.MenuItems.Add("Exit");
               // How do I add an icon to this context menu item?
             }
            notifyIcon.ContextMenu =  notifyContextMenu;
          }
     }

回答1:


MainMenu/ContextMenu are obsolete, you should use the menu strip classes instead.

Change

notifyContextMenu = new System.Windows.Forms.ContextMenu();
notifyContextMenu.MenuItems.Add("Exit");

to

notifyContextMenu = new System.Windows.Forms.ContextMenuStrip();
var exitMenuItem = notifyContextMenu.Items.Add("Exit");
exitMenuItem.Image = ...;

http://msdn.microsoft.com/en-us/library/system.windows.forms.toolstripitem.image.aspx

Finally attach the context menu strip to notify icon,

notifyIcon.ContextMenuStrip = notifyContextMenu;



回答2:


Lex Li's answer covers the simplest way to do this: switch from the MainMenu control to the MenuStrip control, which provides built-in, out-of-the-box support for adding icons to each menu item. Unfortunately, as I discussed in a comment to his answer, this solution has some ugly consequences.

In particular, if you use the MenuStrip control, your menus will forever look ugly and out of place on newer versions of Windows because they're custom drawn by .NET code that will probably never be updated. Sure, they look slick on Windows XP, but that's been old news for at least 5 years. Menus look totally different starting with Windows Vista, and that's what your user will expect from your app, too. The coolest icons in the world just won't help you look any more modern. Compare:

               

So the somewhat more involved solution is to stick with the MainMenu control, which actually uses menus drawn by Windows itself, but write some code that handles adding an icon.

And fortunately, Wyatt O'Day has already written a great custom control that does this for you. All you have to do is download it, drop it into your project, compile, and start using it. It's open-source, licensed under the BSD license, and it produces menus that look platform native on all versions of Windows. Download it here from his website, or start with his introduction and 100% accurate rant.

The results are awesome:

               




回答3:


You can use function SetMenuItemInfo to add icon to menu items.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    class Program
    {
        static void Main()
        {
            var menu = new ContextMenu();
            menu.Popup += MenuItem_Popup;
            SetMenuInfo(menu.Handle, new MENUINFO());
            var item = menu.MenuItems.Add("Exit", (sender, e) => Application.Exit());
            SetImage(item, Properties.Resources.Image1);

            var notifyIcon = new NotifyIcon
            {
                Icon = Properties.Resources.Icon1,
                ContextMenu = menu
            };
            notifyIcon.Visible = true;
            Application.Run();
            notifyIcon.Visible = false;
        }

        static Dictionary<MenuItem, IntPtr> MenuBitmaps = new Dictionary<MenuItem, IntPtr>();

        static void SetImage(MenuItem item, Image img)
        {
            using (var bmp = new Bitmap(img.Width, img.Height, PixelFormat.Format32bppPArgb))
            {
                using (var g = Graphics.FromImage(bmp)) g.DrawImage(img, 0, 0);
                MenuBitmaps[item] = bmp.GetHbitmap(Color.FromArgb(0));
            }
        }

        static void MenuItem_Popup(object sender, EventArgs e)
        {
            var info = new MENUITEMINFO();
            int i = 0;
            foreach (MenuItem item in ((Menu)sender).MenuItems)
                if (item.Visible)
                {
                    if (MenuBitmaps.TryGetValue(item, out info.hbmpItem))
                        SetMenuItemInfo(((Menu)sender).Handle, i, true, info);
                    i++;
                }
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern bool SetMenuInfo(IntPtr hMenu, MENUINFO lpcmi);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern bool SetMenuItemInfo(IntPtr hMenu, int uItem, bool fByPosition, MENUITEMINFO lpmii);
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public class MENUINFO
    {
        public int cbSize = Marshal.SizeOf(typeof(MENUINFO));
        public int fMask = 0x10; //MIM_STYLE
        public int dwStyle = 0x4000000; //MNS_CHECKORBMP
        public uint cyMax;
        public IntPtr hbrBack;
        public int dwContextHelpID;
        public IntPtr dwMenuData;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public class MENUITEMINFO
    {
        public int cbSize = Marshal.SizeOf(typeof(MENUITEMINFO));
        public int fMask = 0x80; //MIIM_BITMAP
        public int fType;
        public int fState;
        public int wID;
        public IntPtr hSubMenu;
        public IntPtr hbmpChecked;
        public IntPtr hbmpUnchecked;
        public IntPtr dwItemData;
        public IntPtr dwTypeData;
        public int cch;
        public IntPtr hbmpItem;
    }
}


来源:https://stackoverflow.com/questions/10671585/how-to-add-an-icon-to-system-windows-forms-menuitem

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!