在WPF中使窗口在特定边界内可拖动

3

我有一个WPF子窗口,我使用DragMove()方法允许拖动。然而,我需要仅允许在其父窗口控件的边界内拖动窗口。

有人能提供一种实现此功能的方法吗? 谢谢!

1个回答

5

有两种方法可以实现这个。

使用LocationEnded

如果您处理此事件,可以将顶部或左侧更改为在所有者窗口的边界内。例如:

    private void Window_LocationChanged(object sender, EventArgs e)
    {

        if (this.Left < this.Owner.Left)
            this.Left = this.Owner.Left;

        //... also right top and bottom
        //
    }

这篇文章写起来很简单,但它违反了最小惊讶原则,因为它没有限制拖动窗口,只是在用户松开鼠标按钮时将窗口推回原位。

使用AddHook

正如Pieter在一个类似的问题的答案中指出的那样,你可以与Windows消息交互并阻止拖动窗口。这样做的好处是限制了实际的拖动窗口

以下是我为AddHook方法编写的示例代码。

在加载窗口时添加钩子。

  //In Window_Loaded the handle is there (earlier its null) so this is good time to add the handler 

   private void Window_Loaded(object sender, RoutedEventArgs e)
    {

        WindowInteropHelper helper = new WindowInteropHelper(this);
        HwndSource.FromHwnd(helper.Handle).AddHook(HwndSourceHookHandler);
    } 

在您的处理程序中,您只想寻找移动或移动消息。然后,您将读取lParam矩形并查看其是否越界。如果是,则需要更改lParam矩形的值并将其重新封送回去。为了简洁起见,我仅处理了左侧。您仍需要编写右侧、顶部和底部情况。
 private IntPtr HwndSourceHookHandler(IntPtr hwnd, int msg, IntPtr wParam,
    IntPtr lParam, ref bool handled)
        {


const int WM_MOVING = 0x0216;
        const int WM_MOVE = 0x0003;


        switch (msg)
        {
            case WM_MOVING:
                {


                   //read the lparm ino a struct

                    MoveRectangle rectangle = (MoveRectangle)Marshal.PtrToStructure(
                      lParam, typeof(MoveRectangle));


                     //

                    if (rectangle.Left < this.Owner.Left)
                    {
                        rectangle.Left = (int)this.Owner.Left;
                        rectangle.Right = rectangle.Left + (int)this.Width;
                    }



                    Marshal.StructureToPtr(rectangle, lParam, true);

                    break;
                }
            case WM_MOVE:
                {
                   //Do the same thing as WM_MOVING You should probably enacapsulate that stuff so don'tn just copy and paste

                    break;
                }


        }

        return IntPtr.Zero;

    }
lParam的结构体
  [StructLayout(LayoutKind.Sequential)]
    //Struct for Marshalling the lParam
    public struct MoveRectangle
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;

    }

最后需要注意的一点是,如果您的子窗口允许比父窗口更大,您需要想办法解决此问题。


非常感谢Conrad。我会尝试一下并让您知道结果。 - Dan
@Dan,只是想让您知道,将双精度浮点数转换为整数的强制类型转换可能是可以的。请参见此问题 - Conrad Frix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接