5

コンテキストメニュー項目の1つにアイコンを追加しようとしましたが、追加できませんでした。誰か助けてもらえますか?

これが私が書いたコードです:

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

3 に答える 3

13

Lex Liの答えは、これを行う最も簡単な方法をカバーしています。MainMenuコントロールからコントロールに切り替えますMenuStrip。これにより、各メニュー項目にアイコンを追加するための組み込みのすぐに使用できるサポートが提供されます。残念ながら、私が彼の答えへのコメントで議論したように、この解決策はいくつかの醜い結果をもたらします。

特に、MenuStripコントロールを使用する場合、メニューは、おそらく更新されない.NETコードによってカスタム描画されるため、新しいバージョンのWindowsでは永遠に見苦しくて場違いに見えます。確かに、それらはWindows XPで滑らかに見えますが、それは少なくとも5年間は古いニュースです。メニューはWindowsVistaからはまったく異なって見えますが、それはユーザーがアプリに期待することでもあります。世界で最もクールなアイコンは、あなたがこれ以上現代的に見えるのを助けません。比較:

               MenuStrip(およびその弟であるContextMenuStrip)は、MainMenu(およびその弟であるContextMenu)で実装されたプラットフォームのネイティブメニューと比較して、WindowsVista以降ではまったく見苦しいように見えます。

したがって、もう少し複雑な解決策はMainMenu、実際にはWindows自体によって描画されたメニューを使用するコントロールを使用することですが、アイコンの追加を処理するコードを記述します。

そして幸いなことに、WyattO'Dayはすでにこれを行う優れたカスタムコントロールを作成しています。あなたがしなければならないのはそれをダウンロードし、それをあなたのプロジェクトにドロップし、コンパイルし、そしてそれを使い始めることです。これはオープンソースであり、BSDライセンスの下でライセンスされており、すべてのバージョンのWindowsでプラットフォームネイティブに見えるメニューを生成します。彼のウェブサイトからここにダウンロードするか、彼の紹介と100%正確な暴言から始めてください。

結果は素晴らしいです:

               4つの異なるオペレーティングシステム(Windows 7、Vista、XP、および2000)でのWyattのVistaMenuコントロールの外観を比較します。4つすべてで、アイコンを除いて、プラットフォームのネイティブメニューと同じように見えます。

于 2012-05-20T09:06:03.893 に答える
8

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;
于 2012-05-20T08:18:59.177 に答える
2

関数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;
    }
}
于 2018-10-23T18:11:22.070 に答える