1

我有一个紧凑的框架表单应用程序,除其他外,它显示不是完整窗口大小的弹出窗口。

就目前情况而言,当显示这些弹出窗口之一时,可以使用标题栏将其拖出可见屏幕区域。然后,这给人的印象是表单没有响应,因为弹出窗口正在等待输入但不可见。

因此,我想检测表单的移动,以便我可以重置位置并将其保持在屏幕中央。但是,我似乎无法做到这一点。

到目前为止,我已经尝试对表单进行子分类,然后查找 WM_MOVE、WM_SIZE 或 WM_WINDOWPOSCHANGED 消息 - 但是我从未在 WndProc 中看到这些消息(我也尝试过记录所有消息,但是一旦显示表单,它就不会收到任何消息移动或移动后,实际上一旦在 WndProc 中显示下一条消息,就是在表单上单击按钮时)。

我还尝试在 OnPaint/OnPaintBackground 事件期间检测表单的当前位置。只要窗体不包含 MainMenu 控件,此方法就有效。如果 MainMenu 控件存在,您可以将窗体向下拖动到菜单所在的屏幕底部,并且 OnPaint/OnPaintBackground 事件不再触发(不需要重新绘制,因为它不再可见)。

我的想法不多了;有什么建议么?

4

2 回答 2

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

如果表单被移动并且可能超出主屏幕边界,您应该能够使用代码“识别”。

于 2013-01-18T11:31:06.133 回答
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;
        }
    }
}
于 2013-01-24T13:53:52.653 回答