ymbcKxSw
ymbcKxSw

Reputation: 325

How to position a window on multi-monitor displays in WPF?

I'm trying to position a window in the top right corner of my secondary display. In the Window_Loaded event handler, I have the following code:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    this.Left = Screen.AllScreens[1].WorkingArea.Left;
    this.Top = Screen.AllScreens[1].WorkingArea.Top;
}

This works perfectly well when both my displays have a scale factor of 100%, but as soon as I change the scale of the primary display, the window loads completely offscreen.

Does anyone know a way to absolutely position a window in WPF? Most of the answers I found are pre-Win8.1 and don't have to worry about scaling. I can't seem to figure out the pattern behind the Top and Left properties.

Upvotes: 5

Views: 9396

Answers (3)

geraphl
geraphl

Reputation: 315

I have found a solution to this problem on CodeProject at Wpf windows on two screens. Check that link for further details and more in-depth solutions.

The solution for me was to calculate the ratio between the real resolution and the WorkingArea's resolution, and requires using System.Windows.Forms.

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    var scaleRatio = Math.Max(Screen.PrimaryScreen.WorkingArea.Width / SystemParameters.PrimaryScreenWidth,
                Screen.PrimaryScreen.WorkingArea.Height / SystemParameters.PrimaryScreenHeight);
    this.Left = Screen.AllScreens[1].WorkingArea.Left / scaleRatio ;
    this.Top = Screen.AllScreens[1].WorkingArea.Top / scaleRatio ;
}

Upvotes: 9

mcpat
mcpat

Reputation: 11

To center on a screen (multi-monitor) with different dpi, I used this and measured it with an ruler (no joke):

var handle = new System.Windows.Interop.WindowInteropHelper(this).Handle;
var screen = System.Windows.Forms.Screen.FromHandle(handle);
var scaleRatio = Math.Max(VisualTreeHelper.GetDpi(this).DpiScaleX, VisualTreeHelper.GetDpi(this).DpiScaleY);

this.Left = (screen.WorkingArea.Left + (screen.WorkingArea.Width - this.Width * scaleRatio) / 2) / scaleRatio;
this.Top = (screen.WorkingArea.Top + (screen.WorkingArea.Height - this.Height * scaleRatio) / 2) / scaleRatio;

And the WPF form is centered on the actual screen.

To put it to the left side (on Windows 10), then the solution is:

this.Left = screen.WorkingArea.Left/ scaleRatio - SystemParameters.ResizeFrameVerticalBorderWidth - SystemParameters.FixedFrameVerticalBorderWidth;

Upvotes: 0

ymbcKxSw
ymbcKxSw

Reputation: 325

You can do the following

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    var p = this.PointFromScreen(new Point(Screen.AllScreens[1].WorkingArea.X, Screen.AllScreens[1].WorkingArea.Y));
    this.Left += p.X;
    this.Top += p.Y;
}

I figured out that the PointFromScreen function tells you the offset of an absolute coordinate from your window. Pick the position of the top left of your display and you know how much you have to move - but critically it's in the same units as your window's Top and Bottom. This is a pretty narrow case, but it be can extrapolated to positioning in general. Hope it Helps!

Upvotes: 2

Related Questions