使窗口可在某个边界 WPF 内拖动 [英] Make a window draggable within a certain boundary WPF

查看:34
本文介绍了使窗口可在某个边界 WPF 内拖动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 wpf 子窗口,我允许使用 DragMove() 方法拖动它.但是,我需要只允许在其父窗口控件的边界内拖动窗口.

I have a wpf child window that I allow dragging by using the DragMove() method. However, I need to allow the window to be dragged only within the bounds of its Parent window control.

谁能建议一种方法来实现这一目标?谢谢!

Can anyone suggest a way to achieve this? Thanks!

推荐答案

有两种方法可以做到这一点.

There are two ways to do this.

使用 LocationEnded

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

If you handle this event you can change the Top or Left to be within the bounds of the owner window. e.g.

    private void Window_LocationChanged(object sender, EventArgs e)
    {

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

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

这很容易写,但它违反了最小惊讶原则,因为它不绑定拖动窗口,它只是在用户松开鼠标按钮时将窗口推回原位.

This is fairly easy to write, but it violates the Principle of least astonishment as it doesn't bound the drag window it just pushes the window back to place when the user lets go of the mouse button.

使用 AddHook

正如 Pieter 在一个答案中指出的那样类似的问题,您可以与 Windows 消息互操作并阻止拖动窗口.这具有限制实际拖动窗口的良好效果.

As Pieter points out in an answer to a similar question you can Interop to the Windows messaging and block the drag window. This has the nice affect of bounding the actual drag window.

这是我为 AddHook 方法编写的一些示例代码

Here's some sample code I put together for the AddHook approach

从加载的窗口开始添加钩子

Start with the window loaded to add the hook

  //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 矩形的值并将其编组回来.请注意,为简洁起见,我只做了左边.您仍然需要写出正确的、顶部和底部的情况.

In your handler you want to only look for moving or move message. Then you'll read the lParam rectangle and see if it out of bounds. If it is you'll need to change the values of the lParam rectangle and Marshal it back. Note for brevity's sake I only did the left. You'll still need to write out the right, top and bottom cases.

 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;

    }

最后一个注意事项,如果允许子窗口大于父窗口,您需要弄清楚该怎么做.

One final note you'll need to figure out what to do if you Child window is allowed to be bigger than the parent window.

这篇关于使窗口可在某个边界 WPF 内拖动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆