如何将图标添加到System.Windows.Forms.MenuItem?

时间:2012-05-20 07:27:50

标签: .net winforms menu contextmenu

我尝试在我的某个上下文菜单项中添加一个图标,但我无法做到。有人能帮助我吗?

这是我写的代码:

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

3 个答案:

答案 0 :(得分:10)

Lex Li's answer涵盖最简单的方式:从MainMenu控件切换到MenuStrip控件,该控件提供内置的,不在内的 - 支持为每个菜单项添加图标。不幸的是,正如我在a comment中所讨论的那样,这个解决方案会产生一些难看的后果。

特别是,如果您使用MenuStrip控件,您的菜单将永远看起来很丑,并且在较新版本的Windows上不合适,因为它们是由.NET代码自定义绘制的,可能永远不会更新。当然,他们在Windows XP上看起来很光滑,但这已经是至少5年的旧闻了。从Windows Vista开始,菜单看起来完全不同,这也是您的用户对您的应用程序的期望。世界上最酷的图标不会让你看起来更现代。比较:

MenuStrip (and its little brother, ContextMenuStrip) look downright ugly on Windows Vista and later, compared to the platform native menus, as implemented with MainMenu (and its little brother, ContextMenu)

所以更复杂的解决方案是坚持MainMenu控件,它实际上使用Windows自己绘制的菜单,但是编写一些处理添加图标的代码。

幸运的是,Wyatt O'Day已经为您编写了一个很棒的自定义控件。您所要做的就是下载它,将其放入您的项目,编译并开始使用它。它是开源的,在BSD许可下获得许可,并且它生成的菜单在所有版本的Windows 上看起来都是平台原生的。下载here from his website,或以his introduction and 100% accurate rant开头。

结果 awesome

Comparing the appearance of Wyatt's VistaMenu control on 4 different operating systems: Windows 7, Vista, XP, and 2000. On all 4, it looks just like the platform native menus, except with icons!

答案 1 :(得分:5)

MainMenu / ContextMenu已经过时,您应该使用菜单条类。

更改

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

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

最后附上上下文菜单条以通知图标,

notifyIcon.ContextMenuStrip = notifyContextMenu;

答案 2 :(得分:0)

您可以使用SetMenuItemInfo函数将图标添加到菜单项。

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