15

I understand that WPF coordinates are different from "real" screen coodinates (pixel coordinates) if the computer is not using the default DPI setting. In my program I want to (1) figure out which monitor a WPF window is on and (2) open another window in the bottom-left corner of the same monitor. I heard there is no equivalent of Screen for WPF so I use the WinForms version, as follows, which works fine at the default 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;
}

But at other DPIs, both steps work incorrectly, and may put the window completely off-screen.

So far, it looks like I can use Visual.PointToScreen for the first part:

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;

I'm not sure if this is quite right, as it may not account for the borders correctly. But the second part is more important. How do I convert the screen rectangle "scr" into WPF space, in order to set Left and Top correctly?

1
  • 2
    Not sure about multiple monitor support, but you can correctly position your window on the primary screen using only WPF (which is DPI aware) without any references to Windows Forms (which is not DPI aware) using the SystemParameters class. The relevant properties automatically adjust to different DPI settings. Example: window.Top = SystemParameters.FullPrimaryScreenHeight - (window.ActualHeight - SystemParameters.WindowCaptionHeight); //Works on Vista and Windows 7, don't know about XP. Commented Aug 15, 2011 at 5:59

2 Answers 2

33
+100
  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;
    }
    
Sign up to request clarification or add additional context in comments.

3 Comments

Added RealPixelsToWpf() helper method.
Does not solve my issue. WPF reports my screen as 1936x1040, whereas Windows actually has it at 1920x1024. Transform() in my case is a no-op.
After much investigation, the solution: WPF fullscreen windows actually ARE larger than the screen. There is a virtual border around them which represents the full extent of the window. So this is not a scaling issue, but a matter of adding/subtracting the size of that border region. I don't know a general method, but for now just looking at the values and making the correction.
2

Does this work if you place it in the code-behind for your Window?

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;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.