我有一个紧凑的框架表单应用程序,除其他外,显示不是完整窗口大小的弹出窗口。
根据情况,当显示其中一个弹出窗口时,可以使用标题栏将其拖离可见屏幕区域。然后,这给人的印象是表单没有响应,因为弹出窗口正在等待输入但不可见。
因此,我想检测表单的移动,以便我可以重置位置并使其保持在屏幕中心。但是,我似乎无法实现这一目标。
到目前为止,我已尝试对表单进行子类化,然后查找WM_MOVE,WM_SIZE或WM_WINDOWPOSCHANGED消息 - 但是我从未在WndProc中看到这些消息(我还尝试记录所有消息但是一旦表单显示它接收移动时或移动后没有消息,实际上一旦显示WndProc中的下一条消息就是在表单上单击按钮时。)
我还尝试在OnPaint / OnPaintBackground事件期间检测表单的当前位置。只要表单不包含MainMenu控件,这就有效。如果MainMenu控件存在,您可以将窗体向下拖动到菜单所在位置的屏幕底部,并且OnPaint / OnPaintBackground事件不再触发(不需要重新绘制,因为它不再可见)。
我的想法已经不多了;有什么建议吗?
答案 0 :(得分:4)
我刚刚更新了我的Moveable WinForm解决方案:http://www.hjgode.de/wp/2012/11/07/mobile-development-move-your-form/。
更新的源代码位于http://code.google.com/p/win-mobile-code/source/browse/#svn%2Ftrunk%2FMoveableWinForm%2FMovableForm
将msg发送到表单的基本子类代码是(参见winapi.cs):
#region subclassing
public class subclassForm:IDisposable
{
#region delegate_event_stuff
public class wndprocEventArgs : EventArgs
{
public IntPtr hWnd;
public uint msg;
public IntPtr lParam;
public IntPtr wParam;
public wndprocEventArgs(IntPtr lphWnd, uint iMsg, IntPtr lpLParam, IntPtr lpWParam)
{
hWnd = lphWnd;
msg = iMsg;
lParam = lpLParam;
wParam = lpWParam;
}
}
public delegate void wndProcEventHandler(object sender, wndprocEventArgs wndProcArgs);
public event wndProcEventHandler wndProcEvent;
void onWndProcEvent(wndprocEventArgs wa)
{
if (this.wndProcEvent == null)
return;
wndProcEvent(this, wa);
}
#endregion
public enum WNDMSGS:uint{
WM_MOVE=0x0003,
WM_SIZE=0x0005,
}
public subclassForm(System.Windows.Forms.Form form)
{
_form = form;
lpPrevWndFunc = _subClassForm(_form);
}
public void Dispose()
{
unsubClassForm(_form);
}
IntPtr lpPrevWndFunc=IntPtr.Zero;
System.Windows.Forms.Form _form;
static WndProcDelegate persistentWndProc;
IntPtr _subClassForm(System.Windows.Forms.Form form)
{
//avoid multiple subclassing
if (lpPrevWndFunc != IntPtr.Zero)
return IntPtr.Zero;
persistentWndProc = WndProc;
lpPrevWndFunc = (IntPtr)GetWindowLong(form.Handle, GWL_WNDPROC);
SetWindowLong(form.Handle, GWL_WNDPROC, persistentWndProc);
return lpPrevWndFunc;
}
IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
System.Diagnostics.Debug.WriteLine("HWND: " + hWnd + " MSG: " + msg + " WPARAM: " + wParam + " LPARAM: " + lParam);
onWndProcEvent(new wndprocEventArgs(hWnd, msg, lParam, wParam));
return CallWindowProc(lpPrevWndFunc, hWnd, msg, wParam, lParam);
}
bool unsubClassForm(System.Windows.Forms.Form form)
{
bool bRet = false;
if (lpPrevWndFunc == IntPtr.Zero)
return bRet;
if (SetWindowLong(form.Handle, GWL_WNDPROC, lpPrevWndFunc.ToInt32()) != 0)
{
bRet = true;
lpPrevWndFunc = IntPtr.Zero;
}
return bRet;
}
}
#endregion
如果表单被移动并且可能在主要屏幕边界之外,您应该能够“识别”代码。
答案 1 :(得分:0)
这是一个愚蠢的解决方案,但你考虑过在表格上放一个计时器吗?
public partial class Form1 : Form
{
private Timer CheckLocation { get; set; }
private Point FirstLocation { get; set; }
public Form1()
{
InitializeComponent();
FirstLocation = Location;
CheckLocation.Tick += new EventHandler(CheckLocation_Tick);
}
void CheckLocation_Tick(object sender, EventArgs e)
{
if (FirstLocation != Location)
{
Location = FirstLocation;
}
}
}