在我的一些应用程序中,我使用 WS_EX_NOACTIVATE extended window style value (例如,创建虚拟键盘或用于另一个程序中托管的表单)。此值可防止表单获得焦点。
下面是我的处理方式:
protected override CreateParams CreateParams
{
get
{
CreateParams p = base.CreateParams;
p.ExStyle |= Win32.WS_EX_NOACTIVATE;
return p;
}
}
它运行良好,但我注意到此解决方案有两个问题:
- 用户不能通过按“Tab”键在控件之间移动
- 当用户拖动表单时,我们看不到位移(移动过程中表单不会重绘)
那么,是否有可能解决这些问题,或者至少实现一些替代方案?也许 WS_EX_NOACTIVATE 不是最好的解决方案?
非常感谢!
以下是我为每个问题找到的解决方案:
问题#1:
protected override bool ProcessKeyPreview(ref Message m)
{
if (m.Msg == Win32.WM_KEYDOWN && (Keys)m.WParam == Keys.Tab)
{
if (Control.ModifierKeys == Keys.Shift)
{
this.SelectNextControl(ActiveControl, false, true, true, true); // Bring focus to previous control
}
else
{
this.SelectNextControl(ActiveControl, true, true, true, true); // Bring focus to next control
}
}
return base.ProcessKeyPreview(ref m);
}
问题 #2:您必须拦截从系统接收到的适当消息(WM_SIZING
和 WM_MOVING
)并设置表单的位置SetWindowPos()
- 这将强制它移动!
在您的表单类中:
public const int WM_SIZING = 0x0214;
public const int WM_MOVING = 0x0216;
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInstertAfter, int x, int y, int cx, int cy, uint flags);
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_SIZING || m.Msg == WM_MOVING)
{
RECT rect = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
SetWindowPos(this.Handle, IntPtr.Zero, rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top, 0);
}
else
{
base.WndProc(ref m);
}
}
我是一名优秀的程序员,十分优秀!