2009-02-20 4 views
1

просто интересно, знаете ли вы каким-либо способом установить границу перетаскивания для окна?WPF Window Drag/Move Boundary

Было бы неплохо иметь эти свойства:

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

Те состоят из свойств, кстати, что было бы неплохо иметь.

Я знаю, что я мог бы установить таймер, чтобы стрелять из 10-й секунды, и проверить слева и сверху, а затем переместить его, если он закончится. Но было бы более элегантно, если бы окно действовало так, как будто оно ударилось о стену, и не может идти дальше, например, переходить к краю экрана или что-то подобное.

Редакция: Кажется, что где-то есть какая-то путаница, точка, которую я пытаюсь сделать, находится в абзаце выше, перетаскивая, а не изменяя размер.

ответ

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 

Это сделал перетаскиваемое окно остается на основном экране (в целом окне), но вы можете легко изменить границы на любые значения, которые вам нужны.

+0

Я пробовал это раньше, но событие Window_LocationChanged происходит ПОСЛЕ того, как окно уже перемещено на экране, поэтому это создает резкий визуальный эффект, когда вид окна мерцает или прыгает, когда он начинает переходить через некоторый предел, потому что он изначально получает вырисовывается «вне границ», а затем перерисовывается обратно туда, где вы этого хотите. – user316117

+0

Как предотвратить мерцание окна? Движение перетаскивания не является гладким. – Abhishek

0

Для этой цели существуют свойства зависимостей для окна WPF.

Вот они:

  • Window.MaxWidth
  • Window.MaxHeight

Эти свойства ограничивают размер окна, так же, как Форме Winform в.

+0

Я говорю о перетаскивании окна по экрану, а не его повторной калибровке. Подумайте о настройке области на экране, окно разрешено только перемещаться, даже если ваш экран больше. Как контейнер с контейнером лучше всего я могу думать. – ScottN

+0

Я сижу здесь, читая это снова, и задаюсь вопросом, неправильно ли я задал вопрос и как вы могли подумать, что я говорю о размере окна и не перетаскиваю, я даже не упоминаю слово «размер» или «размерный размер» в мой вопрос ... – ScottN

+0

Перемещение границы? Я думаю, что это по умолчанию перетаскивается. Вы хотите перетащить ручку, как в Windows Forms? –

0

Возможно, вы могли бы обработать PreviewMouseMove (либо событие, либо переопределить соответствующий защищенный метод), и установить e.Handled = true всякий раз, когда движение мыши приведет к перемещению окна за пределами региона, к которому вы хотите ограничить его.

Это похоже на самый логичный, похожий на WPF способ сделать это.

2

Вот «магия», вам нужно создать эту функциональность, все, что вам нужно сделать, это установить метод 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; 
} 
+0

Привет. Что такое 'SWP', если' ((pos.flags & (int) SWP.NOMOVE)!= 0) '? он должен быть объявлен как правое перечисление? 'internal enum SWP { NOMOVE = 0x0002 }' Можете привести рабочий пример, пожалуйста? – Abhishek