如何将WPF窗口捕捉到屏幕边缘

vaqhlq81  于 2023-04-22  发布在  其他
关注(0)|答案(1)|浏览(186)

我写了这段代码,但只有我的多显示器设置的顶部和左侧正在捕捉。屏幕的底部和右侧边缘以及显示器之间的中间边缘被忽略。我如何捕捉到这些边缘?

using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Runtime.InteropServices;

namespace MyTimer
{
    public partial class MainWindow
    {
        Point LastLeftClickPosition = new Point ( );
        int SnapThresholdInPixels = 20;

        void Window_MouseLeftButtonDown ( object sender, MouseButtonEventArgs e )
        {
            this.LastLeftClickPosition = e.GetPosition ( this );
            Mouse.Capture ( this );
        }

        void Window_MouseLeftButtonUp ( object sender, MouseButtonEventArgs e )
        {
            Mouse.Capture ( null );
        }

        void Window_MouseMove ( object sender, MouseEventArgs e )
        {
            if ( e.LeftButton == MouseButtonState.Pressed )
            {
                var currentPosition = e.GetPosition ( this );

                var deltaX = currentPosition.X - this.LastLeftClickPosition.X;
                var deltaY = currentPosition.Y - this.LastLeftClickPosition.Y;

                Left += deltaX;
                Top += deltaY;

                this.SnapWindow ( );
            }
        }

        void SnapWindow ( )
        {
            var screens = System.Windows.Forms.Screen.AllScreens;

            foreach ( var screen in screens )
            {
                var workingArea = screen.WorkingArea;

                if ( Math.Abs ( this.Left - workingArea.Left ) < this.SnapThresholdInPixels )
                    this.Left = workingArea.Left;

                if ( Math.Abs ( this.Top - workingArea.Top ) < this.SnapThresholdInPixels )
                    this.Top = workingArea.Top;

                if ( Math.Abs ( this.Left + this.ActualWidth - workingArea.Right ) < this.SnapThresholdInPixels )
                    this.Left = workingArea.Right - ActualWidth;

                if ( Math.Abs ( this.Top + this.ActualHeight - workingArea.Bottom ) < this.SnapThresholdInPixels )
                    this.Top = workingArea.Bottom - ActualHeight;

        }
    }
}
uttx8gqw

uttx8gqw1#

从你发布的代码中,我们还不清楚为什么行为不像预期的那样。我们只能假设。例如,交换屏幕对齐。
您可以尝试以下代码来查看它是否修复了该问题。该示例显式检测Window被拖动到的当前屏幕。它还补偿了主屏幕和辅助屏幕顺序交换的情况(这将导致负屏幕位置以指示交换的顺序)。
您还应该考虑覆盖从UIElement继承的输入事件处理程序,而不是将自定义事件处理程序附加到事件:

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
  this.LastLeftClickPosition = e.GetPosition(this);
  _ = Mouse.Capture(this);
}

protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) 
  => Mouse.Capture(null);

protected override void OnMouseMove(MouseEventArgs e)
{
  if (e.LeftButton == MouseButtonState.Pressed)
  {
    Point currentPosition = e.GetPosition(this);

    double deltaX = currentPosition.X - this.LastLeftClickPosition.X;
    double deltaY = currentPosition.Y - this.LastLeftClickPosition.Y;

    this.Left += deltaX;
    this.Top += deltaY;

    SnapWindow();
  }
}

void SnapWindow()
{
  var windowAnchor = new System.Drawing.Point((int)this.Left, (int)this.Top);
  var windowBounds = new System.Drawing.Rectangle(windowAnchor, new System.Drawing.Size((int)this.RenderSize.Width, (int)this.RenderSize.Height));

  System.Drawing.Rectangle screenBounds = GetCurrentScreenNormalized(windowBounds);

  // Left bounds check
  if (Math.Abs(windowBounds.Left - screenBounds.Left) < this.SnapThresholdInPixels)
  {
    this.Left = Math.Abs(screenBounds.Left);
  }

  // Right bounds check
  if (Math.Abs(windowBounds.Right - screenBounds.Right) < this.SnapThresholdInPixels)
  {
    this.Left = Math.Abs(screenBounds.Right - windowBounds.Width);
  }

  // Top bounds check
  if (Math.Abs(windowBounds.Top - screenBounds.Top) < this.SnapThresholdInPixels)
  {
    this.Top = Math.Abs(screenBounds.Top);
  }

  // Bottom bounds check
  if (Math.Abs(windowBounds.Bottom - screenBounds.Bottom) < this.SnapThresholdInPixels)
  {
    this.Top = Math.Abs(screenBounds.Bottom - windowBounds.Height);
  }
}

private System.Drawing.Rectangle GetCurrentScreenNormalized(System.Drawing.Rectangle windowBounds)
{
  System.Windows.Forms.Screen currentScreen = System.Windows.Forms.Screen.AllScreens
    .First(screen => screen.WorkingArea.IntersectsWith(windowBounds));

  // Normalize screen coordinates:
  // Use absolute coordinates to compensate the case that the secondary screen is left from the primary screen.
  // This would result in negative (inverted) coordinates for the secondary screen.
  // For example top-left becomes S1(-1920;0) and not S1(1920;0) as one would expect.
  // But positioning an object at this negative coordinates results in effectigvely placing the object outside the screen bounds.
  // The negative-sign is inly symbolic to indicate the screen order.
  var normalizedScreenLocation = new System.Drawing.Point(Math.Abs(currentScreen.WorkingArea.Left), Math.Abs(currentScreen.WorkingArea.Top));
  var normalizedScreenBounds = new System.Drawing.Rectangle(normalizedScreenLocation, currentScreen.WorkingArea.Size);
  return normalizedScreenBounds;
}

相关问题