WPF窗口拖动/移动边界

时间:2009-02-20 01:56:44

标签: wpf winforms

只是好奇你是否知道为窗口设置拖动边界的任何方法?

拥有这些属性会很好:

Me.MinLeft = 10
Me.MinTop = 10
Me.MaxLeft = 150
Me.MaxTop = 150

这些是属性,btw ,这样会很好。

我知道我可能会设置一个定时器来启动10秒钟并检查左侧和顶部,然后如果它结束则将其移回。但是让窗户像撞墙一样更加优雅,不能走得更远,比如移动到屏幕的边缘或者类似的东西。

编辑:某处似乎有些混乱,我试图在上面的段落中拖拽,而不是重新调整大小。

4 个答案:

答案 0 :(得分:3)

这是您需要创建此功能的“魔法”,您只需将Window_SourceInitialized方法设置为窗口的SourceInitialized事件,并将逻辑插入到大评论的位置。

我将来自多个来源的代码组合在一起,因此可能会出现一些语法错误。

internal enum WM
{
   WINDOWPOSCHANGING = 0x0046,
}

[StructLayout(LayoutKind.Sequential)]
internal struct WINDOWPOS
{
   public IntPtr hwnd;
   public IntPtr hwndInsertAfter;
   public int x;
   public int y;
   public int cx;
   public int cy;
   public int flags;
}

private void Window_SourceInitialized(object sender, EventArgs ea)
{
   HwndSource hwndSource = (HwndSource)HwndSource.FromVisual((Window)sender);
   hwndSource.AddHook(DragHook);
}

private static IntPtr DragHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handeled)
{
   switch ((WM)msg)
   {
      case WM.WINDOWPOSCHANGING:
      {
          WINDOWPOS pos = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
          if ((pos.flags & (int)SWP.NOMOVE) != 0)
          {
              return IntPtr.Zero;
          }

          Window wnd = (Window)HwndSource.FromHwnd(hwnd).RootVisual;
          if (wnd == null)
          {
             return IntPtr.Zero;
          }

          bool changedPos = false;

          // ***********************
          // Here you check the values inside the pos structure
          // if you want to override tehm just change the pos
          // structure and set changedPos to true
          // ***********************

          if (!changedPos)
          {
             return IntPtr.Zero;
          }

          Marshal.StructureToPtr(pos, lParam, true);
          handeled = true;
       }
       break;
   }

   return IntPtr.Zero;
}

答案 1 :(得分:2)

我毫不怀疑Nir的答案会花一点时间来实现它,我能够用这段代码做我想要的更优雅:

Private Sub myWindow_LocationChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.LocationChanged

    Dim primaryBounds As System.Drawing.Rectangle = Windows.Forms.Screen.PrimaryScreen.Bounds
    Dim windowBounds As System.Drawing.Rectangle = New System.Drawing.Rectangle(CInt(Me.Left), CInt(Me.Top), CInt(Me.Width), CInt(Me.Height))

    If (windowBounds.Left < 0) Then
        windowBounds = New System.Drawing.Rectangle(0, windowBounds.Top, windowBounds.Width, windowBounds.Height)
    ElseIf (windowBounds.Right > primaryBounds.Right) Then
        windowBounds = New System.Drawing.Rectangle(primaryBounds.Right - windowBounds.Width, windowBounds.Top, windowBounds.Width, windowBounds.Height)
    End If

    If (windowBounds.Top < 0) Then
        windowBounds = New System.Drawing.Rectangle(windowBounds.Left, 0, windowBounds.Width, windowBounds.Height)
    ElseIf (windowBounds.Bottom > primaryBounds.Bottom) Then
        windowBounds = New System.Drawing.Rectangle(windowBounds.Left, primaryBounds.Bottom - windowBounds.Height, windowBounds.Width, windowBounds.Height)
    End If

    Me.Left = windowBounds.Left
    Me.Top = windowBounds.Top

End Sub

这使得被拖动的窗口保持在主屏幕(整个窗口)内,但您可以轻松地将边界更改为您需要的任何值。

答案 2 :(得分:0)

为此目的,WPF的窗口有依赖属性。

他们是:

  • Window.MaxWidth
  • Window.MaxHeight

这些属性将限制Window的大小,就像WinForm的Form一样。

答案 3 :(得分:0)

也许您可以处理PreviewMouseMove(事件或覆盖相应的受保护方法)并设置e.Handled = true,只要鼠标移动会导致窗口移动到您想要约束它的区域之外。

这似乎是最合乎逻辑的WPF方式。