将WM消息从子控件发送到其父窗体

时间:2016-02-16 01:35:10

标签: c# winforms wndproc

我有一个无边框 #if,其中Form停靠在顶部(就好像它是标题栏)。到目前为止一切正常,除了我自己无法弄清楚的一个问题。

我必须在Panel的{​​{1}}事件中关注代码才能移动MouseDown

Panel

当然导入外部API后:

Form

我还覆盖了SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0); 的{​​{1}}方法,以便能够像Windows中的任何其他常规格式一样调整[DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); 的大小(取自SO帖子,找不到)现在的链接):

WndProc

现在上面的代码工作正常,唯一的问题是上边框,因为Form的上半部分被Form覆盖。所以我认为我可以在窗格的protected override void WndProc(ref Message m) { if (!_resizable) { base.WndProc(ref m); return; } const UInt32 WM_NCHITTEST = 0x0084; const UInt32 WM_MOUSEMOVE = 0x0200; const UInt32 HTLEFT = 10; const UInt32 HTRIGHT = 11; const UInt32 HTBOTTOMRIGHT = 17; const UInt32 HTBOTTOM = 15; const UInt32 HTBOTTOMLEFT = 16; const UInt32 HTTOP = 12; const UInt32 HTTOPLEFT = 13; const UInt32 HTTOPRIGHT = 14; const int RESIZE_HANDLE_SIZE = 10; bool handled = false; if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE) { Size formSize = this.Size; Point screenPoint = new Point(m.LParam.ToInt32()); Point clientPoint = this.PointToClient(screenPoint); Dictionary<UInt32, Rectangle> boxes = new Dictionary<UInt32, Rectangle>() { {HTBOTTOMLEFT, new Rectangle(0, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTBOTTOM, new Rectangle(RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTBOTTOMRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE)}, {HTTOPRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, 0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTTOP, new Rectangle(RESIZE_HANDLE_SIZE, 0, formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTTOPLEFT, new Rectangle(0, 0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTLEFT, new Rectangle(0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE) } }; foreach (KeyValuePair<UInt32, Rectangle> hitBox in boxes) { if (this.WindowState != FormWindowState.Maximized && hitBox.Value.Contains(clientPoint)) { m.Result = (IntPtr)hitBox.Key; handled = true; break; } } } if (!handled) base.WndProc(ref m); else this.Refresh(); } Form事件中执行类似的操作,以使Windows认为事件来自表单。

Panel事件中:

MouseDown

MouseMove事件中:

MouseDown

这是const int WM_NCLBUTTONDOWN = 0xA1; (sender as Control).Capture = false; Int32 lparam = MakeLParam(e.X, e.Y); Message msg = Message.Create(Handle, WM_NCLBUTTONDOWN, IntPtr.Zero, (IntPtr)lparam); WndProc(ref msg); 方法:

MouseMove

无论如何,它只是不起作用。

如何让Windows相信鼠标移动/点击来自表单本身而不是来自面板?

1 个答案:

答案 0 :(得分:0)

我在different forum找到了解决方案。这很简单。基本上,您将处理MouseMove事件,然后手动发送调整大小消息,而不是传递所有子控件消息。秘诀在于发送WM_NCLBUTTONDOWN消息以及方向。

这是一个示例代码(在VB.NET中,但我认为所有C#编码员都很容易理解它):

Private Sub Form1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
    'Calculate which direction to resize based on mouse position

    If e.Location.X < BorderWidth And e.Location.Y < BorderWidth Then
        resizeDir = ResizeDirection.TopLeft

    ElseIf e.Location.X < BorderWidth And e.Location.Y > Me.Height - BorderWidth Then
        resizeDir = ResizeDirection.BottomLeft

    ElseIf e.Location.X > Me.Width - BorderWidth And e.Location.Y > Me.Height - BorderWidth Then
        resizeDir = ResizeDirection.BottomRight

    ElseIf e.Location.X > Me.Width - BorderWidth And e.Location.Y < BorderWidth Then
        resizeDir = ResizeDirection.TopRight

    ElseIf e.Location.X < BorderWidth Then
        resizeDir = ResizeDirection.Left

    ElseIf e.Location.X > Me.Width - BorderWidth Then
        resizeDir = ResizeDirection.Right

    ElseIf e.Location.Y < BorderWidth Then
        resizeDir = ResizeDirection.Top

    ElseIf e.Location.Y > Me.Height - BorderWidth Then
        resizeDir = ResizeDirection.Bottom

    Else
        resizeDir = ResizeDirection.None
    End If
End Sub

Private Sub Form1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
    If e.Button = Windows.Forms.MouseButtons.Left And Me.WindowState <> FormWindowState.Maximized Then
        ResizeForm(resizeDir)
    End If
End Sub

Private Sub ResizeForm(ByVal direction As ResizeDirection)
    Dim dir As Integer = -1
    Select Case direction
        Case ResizeDirection.Left
            dir = HTLEFT
        Case ResizeDirection.TopLeft
            dir = HTTOPLEFT
        Case ResizeDirection.Top
            dir = HTTOP
        Case ResizeDirection.TopRight
            dir = HTTOPRIGHT
        Case ResizeDirection.Right
            dir = HTRIGHT
        Case ResizeDirection.BottomRight
            dir = HTBOTTOMRIGHT
        Case ResizeDirection.Bottom
            dir = HTBOTTOM
        Case ResizeDirection.BottomLeft
            dir = HTBOTTOMLEFT
    End Select

    If dir <> -1 Then
        ReleaseCapture()
        SendMessage(Me.Handle, WM_NCLBUTTONDOWN, dir, 0)
    End If
End Sub