【问题标题】:Make a window draggable within a certain boundary WPF使窗口在特定边界 WPF 内可拖动
【发布时间】:2011-02-07 20:30:42
【问题描述】:

我有一个允许使用 DragMove() 方法拖动的 wpf 子窗口。 但是,我需要允许仅在其父窗口控件的范围内拖动窗口。

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

【问题讨论】:

    标签: wpf wpf-controls


    【解决方案1】:

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

    使用LocationEnded

    如果您处理此事件,您可以将 Top 或 Left 更改为在所有者窗口的范围内。 例如

        private void Window_LocationChanged(object sender, EventArgs e)
        {
    
            if (this.Left < this.Owner.Left)
                this.Left = this.Owner.Left;
    
            //... also right top and bottom
            //
        }
    

    这很容易编写,但它违反了Principle of least astonishment,因为它没有绑定拖动窗口,它只是在用户松开鼠标按钮时将窗口推回原位。

    使用AddHook

    正如 Pieter 在 an answer 中指出的类似问题,您可以与 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;
    
        }
    

    最后一点,如果允许子窗口大于父窗口,您需要弄清楚该怎么做。

    【讨论】:

    • 非常感谢康拉德。我会试试这个,让你知道。
    • @Dan 只是为了让你知道从双打到整数的转换可能没问题。见this question
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-07
    • 1970-01-01
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-03
    相关资源
    最近更新 更多