メニュー項目を右クリックしたときにコンテキストメニューを表示する方法
-
07-07-2019 - |
質問
MFCアプリケーションを.NET WinFormsに移植しています。 MFCアプリケーションでは、メニューまたはコンテキストメニュー項目を右クリックすると、診断および構成項目を含む別のコンテキストメニューが表示されます。この機能を.NETに移植しようとしていますが、問題があります。
右クリックをキャプチャし、基になるメニューのクリックを無効にし、適切な場所にコンテキストメニューをポップアップできましたが、元のメニューはフォーカスを失うとすぐに消えます。
MFCでは、 TPM_RECURSE フラグを指定して TrackPopupMenuEx を呼び出すことにより、新しいコンテキストメニューを表示します。
.NETのContextMenu および新しい ContextMenuStrip クラスには、 Show メソッドのみがあります。 .NETでこれを行う方法を知っている人はいますか?
編集
p / invokeを使用して TrackPopupMenuEx を使用しようとしましたが、アプリケーション内の外に見えるContextMenuStripではなくContextMenuを使用することに制限されます。また、まだ正しく機能しません。新しい MenuStrip および ContextMenuStrip では機能しません。
ToolStripMenuItemをサブクラス化して、コンテキストメニューを追加できるかどうかも確認しました。これは MenuStrip で機能しますが、 ContextMenuStrip では、右クリックイベントをクリックとしてパススルーできます。
解決
コメントによる編集:
In:
protected override void OnClick(EventArgs e)
{
if (SecondaryContextMenu == null || MouseButtons != MouseButtons.Right)
{
base.OnClick(e);
}
}
この部分
MouseButtons != MouseButtons.Right
Control.MouseButtonsの呼び出しであるため、コンパイルする必要があります。フォームはControlクラスを継承するため、MouseButtonsプロパティを直接呼び出すだけで十分です。
これが役立つことを願って:
public partial class Form1 : Form
{
class CustomToolStripMenuItem : ToolStripMenuItem
{
private ContextMenuStrip secondaryContextMenu;
public ContextMenuStrip SecondaryContextMenu
{
get
{
return secondaryContextMenu;
}
set
{
secondaryContextMenu = value;
}
}
public CustomToolStripMenuItem(string text)
: base(text)
{ }
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (secondaryContextMenu != null)
{
secondaryContextMenu.Dispose();
secondaryContextMenu = null;
}
}
base.Dispose(disposing);
}
protected override void OnClick(EventArgs e)
{
if (SecondaryContextMenu == null || MouseButtons != MouseButtons.Right)
{
base.OnClick(e);
}
}
}
class CustomContextMenuStrip : ContextMenuStrip
{
private bool secondaryContextMenuActive = false;
private ContextMenuStrip lastShownSecondaryContextMenu = null;
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (lastShownSecondaryContextMenu != null)
{
lastShownSecondaryContextMenu.Close();
lastShownSecondaryContextMenu = null;
}
}
base.Dispose(disposing);
}
protected override void OnControlAdded(ControlEventArgs e)
{
e.Control.MouseClick += new MouseEventHandler(Control_MouseClick);
base.OnControlAdded(e);
}
protected override void OnControlRemoved(ControlEventArgs e)
{
e.Control.MouseClick -= new MouseEventHandler(Control_MouseClick);
base.OnControlRemoved(e);
}
private void Control_MouseClick(object sender, MouseEventArgs e)
{
ShowSecondaryContextMenu(e);
}
protected override void OnMouseClick(MouseEventArgs e)
{
ShowSecondaryContextMenu(e);
base.OnMouseClick(e);
}
private bool ShowSecondaryContextMenu(MouseEventArgs e)
{
CustomToolStripMenuItem ctsm = this.GetItemAt(e.Location) as CustomToolStripMenuItem;
if (ctsm == null || ctsm.SecondaryContextMenu == null || e.Button != MouseButtons.Right)
{
return false;
}
lastShownSecondaryContextMenu = ctsm.SecondaryContextMenu;
secondaryContextMenuActive = true;
ctsm.SecondaryContextMenu.Closed += new ToolStripDropDownClosedEventHandler(SecondaryContextMenu_Closed);
ctsm.SecondaryContextMenu.Show(Cursor.Position);
return true;
}
void SecondaryContextMenu_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
((ContextMenuStrip)sender).Closed -= new ToolStripDropDownClosedEventHandler(SecondaryContextMenu_Closed);
lastShownSecondaryContextMenu = null;
secondaryContextMenuActive = false;
Focus();
}
protected override void OnClosing(ToolStripDropDownClosingEventArgs e)
{
if (secondaryContextMenuActive)
{
e.Cancel = true;
}
base.OnClosing(e);
}
}
public Form1()
{
InitializeComponent();
CustomToolStripMenuItem itemPrimary1 = new CustomToolStripMenuItem("item primary 1");
itemPrimary1.SecondaryContextMenu = new ContextMenuStrip();
itemPrimary1.SecondaryContextMenu.Items.AddRange(new ToolStripMenuItem[] {
new ToolStripMenuItem("item primary 1.1"),
new ToolStripMenuItem("item primary 1.2"),
});
CustomToolStripMenuItem itemPrimary2 = new CustomToolStripMenuItem("item primary 2");
itemPrimary2.DropDownItems.Add("item primary 2, sub 1");
itemPrimary2.DropDownItems.Add("item primary 2, sub 2");
itemPrimary2.SecondaryContextMenu = new ContextMenuStrip();
itemPrimary2.SecondaryContextMenu.Items.AddRange(new ToolStripMenuItem[] {
new ToolStripMenuItem("item primary 2.1"),
new ToolStripMenuItem("item primary 2.2"),
});
CustomContextMenuStrip primaryContextMenu = new CustomContextMenuStrip();
primaryContextMenu.Items.AddRange(new ToolStripItem[]{
itemPrimary1,
itemPrimary2
});
this.ContextMenuStrip = primaryContextMenu;
}
}
他のヒント
おそらく、メソッドをp /呼び出す必要があります。
[DllImport("user32.dll")]
static extern bool TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y,
IntPtr hwnd, IntPtr lptpm);
const int TPM_RECURSE = 0x0001;
これは、複数のContextMenuを使用する方法と、マウスクリックの任意の組み合わせで異なるContextMenuを使用する方法を示しています。