Reputation: 325
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
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
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
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