WPF: 屏幕坐标和WPF坐标之间的转换

14

我知道如果计算机没有使用默认的DPI设置,WPF坐标与“真实”屏幕坐标(像素坐标)是不同的。在我的程序中,我想要(1)找出一个WPF窗口位于哪个显示器上,以及(2)在同一显示器的左下角打开另一个窗口。我听说 WPF 没有类似于Screen的等效物,因此我使用WinForms版本,如下所示,在默认的96 DPI下运行良好:

public void ChooseInitialPosition(Window w) // w is some other window
{
    var scr = System.Windows.Forms.Screen.FromRectangle(
          new System.Drawing.Rectangle((int)w.Left, (int)w.Top, (int)w.Width, (int)w.Height))
          .WorkingArea;

    this.Left = scr.Right - Width;
    this.Top = scr.Bottom - Height;
}

但是在其他DPI下,这两个步骤都会出现错误,并且可能将窗口完全移出屏幕。

到目前为止,看起来我可以使用Visual.PointToScreen来完成第一部分:

var p1 = w.PointToScreen(new Point(0,0));
var p2 = w.PointToScreen(new Point(w.Width,w.Height));
var scr = System.Windows.Forms.Screen.FromRectangle(
    new System.Drawing.Rectangle((int)p1.X, (int)p1.Y, (int)(p2.X - p1.X), (int)(p2.Y - p1.Y))).WorkingArea;

我不确定这是否完全正确,因为它可能没有正确考虑边界。但第二部分更加重要。我如何将屏幕矩形“scr”转换为WPF空间,以便正确设置左和上?


2
不确定是否支持多个监视器,但您可以仅使用WPF(其具有DPI感知能力)而不使用Windows Forms(其没有DPI感知能力)和SystemParameters类正确地将窗口定位在主屏幕上。相关属性会自动调整到不同的DPI设置。示例:window.Top = SystemParameters.FullPrimaryScreenHeight - (window.ActualHeight - SystemParameters.WindowCaptionHeight); //适用于Vista和Windows 7,不确定XP。 - Harlow Burgess
2个回答

31
  1. Which screen a WPF window is on:

    private static Screen GetScreen(Window window)
    {
       return Screen.FromHandle(new WindowInteropHelper(window).Handle);
    }
    
  2. Open another window in the bottom-left corner of the same screen:

    static Point RealPixelsToWpf(Window w, Point p)
    {
        var t = PresentationSource.FromVisual(w).CompositionTarget.TransformFromDevice;
        return t.Transform(p);
    }
    private static void SetPositionBottomLeftCorner(Window sourceWindow, Window targetWindow)
    {
        var workingArea = GetScreen(sourceWindow).WorkingArea;
        var corner = RealPixelsToWpf(sourceWindow, new Point(workingArea.Left, workingArea.Bottom));
        targetWindow.Left = corner.X;
        targetWindow.Top = corner.Y - targetWindow.ActualHeight;
    }
    

2
添加了RealPixelsToWpf()辅助方法。 - Qwertie
无法解决我的问题。 WPF 报告我的屏幕为 1936x1040,而 Windows 实际上将其设置为 1920x1024。在我的情况下 Transform() 是没有效果的。 - Alan Baljeu
经过深入调查,解决方案是:WPF全屏窗口实际上比屏幕大。它们周围有一个虚拟边框,代表窗口的完整范围。因此,这不是一个缩放问题,而是需要添加/减去该边框区域的大小。我不知道一般的方法,但现在只需查看值并进行更正即可。 - Alan Baljeu

2

如果您将此代码放置在窗口的代码后面,它是否有效?

protected override void OnContentRendered(System.EventArgs e)
{
    base.OnContentRendered(e);
    MoveToLowerRightCorner();
}

private void MoveToLowerRightCorner()
{
    var workingArea = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea;
    var transform = PresentationSource.FromVisual(this).CompositionTarget.TransformFromDevice;
    var corner = transform.Transform(new Point(workingArea.Right, workingArea.Bottom));
    this.Left = corner.X - this.ActualWidth;
    this.Top = corner.Y - this.ActualHeight;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接