通常,应用于Winforms控件的Focus概念指示哪个控件对象将接收某些事件,尤其是键盘事件。但是,如果表单或其控件具有已定义的ContextMenuStrip
并且用户右键单击,则菜单将暂时拦截按键事件并阻止它们传递到先前的Focused
控件。
注意,在这种情况下,所讨论的控件不会失去焦点(或rase LostFocus
事件),而是处于某种伪未聚焦状态:例如,TextBox
插入符号将停止闪烁但是一旦菜单关闭将恢复正常行为。
使用从TextBox
派生的自定义控件,并重载WndProc
,DefWinProc
,PreProcessMessage
方法来记录所有可能的Window消息,我看不到要挂钩的消息检测到这种状态。
无论是否显示上下文菜单,调用WinAPI方法GetForegroundWindow()
,GetActiveWindow()
和Win32.GetFocus()
都会返回相同的句柄。
我的问题是:
自定义用户控件是否有任何方法可以检测表单或其任何控件当前是否显示ContextMenuStrip(理想情况下无需迭代所有控件)?
答案 0 :(得分:0)
在离开这个问题一段时间并处理其他事情之后,我发现了一种适度的WinAPI方法来解决这个与C#很好地解决的问题。
这里的魔力是来自WinAPI的SetWinEventHook
函数:
// WINAPI Declarations
const uint EVENT_SYSTEM_MENUSTART = 0x0004;
const uint EVENT_SYSTEM_MENUEND = 0x0005;
const uint EVENT_SYSTEM_MENUPOPUPSTART = 0x0006;
const uint EVENT_SYSTEM_MENUPOPUPEND = 0x0007;
const uint WINEVENT_OUTOFCONTEXT = 0x0000
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
static extern bool UnhookWinEvent(IntPtr hWinEventHook);
// Sample Usage - This version will subscribe to menu events on all processes and all threads:
void StartMonitoringMenus()
{
// The lifetime of these two objects must be the same - we must not let the delegate
// get GC'd before calling UnhookWinEvent at the risk of crashing other processes.
// This sample assumes class fields for these, but could also be static variables
_menuEventCallback = new WinEventDelegate(MenuEventCallback);
_menuEventHook = SetWinEventHook(
EVENT_SYSTEM_MENUSTART,
EVENT_SYSTEM_MENUPOPUPEND,
IntPtr.Zero,
_menuEventCallback,
0,
0,
WINEVENT_OUTOFCONTEXT);
}
void StopMonitoringMenus()
{
// Cleanup Logic
UnhookWinEvent(_menuEventHook);
_menuEventCallback = null;
}
void MenuEventCallback(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
// Do something here like clear focus on poorly behaving hosted native controls
}
引发的特定事件序列取决于所显示菜单的类型。
对于MenuStrip控件:
对于ContextMenuStrips: