Мне нужно программно показать подменю главного меню на форме в приложении Winform .NΕΤ (классы MainMenu с MenuItem).

  • Например. показать подменю со всеми пунктами пункта меню Файл.
  • Например. аналогично нажатию Alt-F, если текст пункта меню - & File.

Я пытался позвонить OnPopup(), PerformClick(), PerformSelect() и отправить сообщение WM_MenuSelect; подменю не открывается.

Как это сделать?

1
Mykola Kovalchuk 4 Дек 2019 в 11:24

2 ответа

Лучший ответ

Чтобы отобразить пункт меню устаревшего MainMenu, вам нужно вызвать TrackPopupMenuEx и передайте ему дескриптор пункта меню. Чтобы отобразить его в правильном месте, например, когда вы нажимаете на элемент меню, получите прямоугольник элемента меню, используя GetMenuItemRect.

enter image description here enter image description here

Вот код:

[DllImport("user32.dll")]
static extern int TrackPopupMenuEx(IntPtr hmenu, uint fuFlags,
    int x, int y, IntPtr hwnd, IntPtr lptpm);
[DllImport("user32.dll")]
static extern bool GetMenuItemRect(IntPtr hWnd, IntPtr hMenu,
    uint uItem, out RECT lprcItem);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
public struct RECT { public int Left, Top, Right, Bottom; }
const int TPM_RIGHTBUTTON = 0x2;
const int TPM_RETURNCMD = 0x100;
const int WM_SYSCOMMAND = 0x112;

public void ShowSubMenu(MenuItem menuItem, bool asContextMenu = false)
{
    var mainMenu = menuItem.GetMainMenu();
    var form = mainMenu.GetForm();
    var x = 0; var y = 0;
    if (asContextMenu)
    {
        x = MousePosition.X; y = MousePosition.Y;
    }
    else
    {
        GetMenuItemRect(form.Handle, mainMenu.Handle, 
            (uint)menuItem.Index, out RECT rect);
        x = rect.Left; y = rect.Bottom;
    }
    var command = TrackPopupMenuEx(menuItem.Handle, TPM_RETURNCMD | TPM_RIGHTBUTTON,
        x, y, form.Handle, IntPtr.Zero);
    if (command > 0)
        SendMessage(form.Handle, WM_SYSCOMMAND, command, IntPtr.Zero);
}

Чтобы использовать это, просто назовите это так:

ShowSubMenu(fileMenuItem);

Если вы вызовете его, передав false showAxContextMenu, оно отобразит подменю в позиции мыши:

ShowSubMenu(fileMenuItem, true);

Примечание. Рекомендуется использовать MenuStrip вместо MainMenu.

3
Reza Aghaei 5 Дек 2019 в 08:17

Вам необходимо клонировать необходимые пункты меню в новый компонент ContextMenu в конструкторе формы или в событии Load и присоединить его к свойству ContextMenu (не ContextMenuStrip) целевого элемента управления.

Например, чтобы клонировать элементы Новый , Открыть и Сохранить из меню Файл в новое {{ X0 } } :

var cmn = new ContextMenu();

cmn.MenuItems.AddRange(
    new[]
    {
        mnuFileNew.CloneMenu(),
        mnuFileOpen.CloneMenu(),
        mnuFileSave.CloneMenu()
    }
);

Или, если они вам нужны:

mnuFile.MenuItems.Cast<MenuItem>().ToList()
    .ForEach(m => cmn.MenuItems.Add(m.CloneMenu()));

Обратите внимание, что подпункты также будут клонированы, если таковые имеются.

И присвойте его свойству ContextMenu:

this.ContextMenu = cmn;

Теперь щелкните правой кнопкой мыши на форме и появится новый ContextMenu, щелкните элемент, и тот же код будет выполнен.

1
JQSOFT 4 Дек 2019 в 12:31