admin管理员组文章数量:1291089
I want a WPF window to cover all monitors.
<Window ... WindowStyle="None" ...
In app.manifest
DPI Awareness is enabled:
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns=";>PerMonitor</dpiAwareness>
<dpiAware xmlns=";>true</dpiAware>
<longPathAware xmlns=";>true</longPathAware>
</windowsSettings>
</application>
The complete area covering all monitors is calculated by finding the outer limits of all Screen.AllScreens
.
Step 1: These screen coordinates are then translated to WPF coordinates using Visual.PointFromScreen
.
var topLeft = PointFromScreen(new Point(o.Left, o.Top));
var bottomRight = PointFromScreen(new Point(o.Right, o.Bottom));
var x1 = Left + topLeft.X;
var y1 = Top + topLeft.Y;
var x2 = Left + bottomRight.X;
var y2 = Top + bottomRight.Y;
var w = x2 - x1;
var h = y2 - y1;
Step 2: Finally the windows is positioned using the calculated coordinates.
Left = x1;
Top = y1;
Width = w;
Height = h;
However this fail with multiple monitors, each having separate DPI scaling.
Eventually I figured out that the output of Visual.PointFromScreen
changes with the monitor the window is located at.
The problem here is in step 2. After setting Left
the window has moved onto another monitor and a new set of coordinates need to be calculated using Visual.PointFromScreen
.
Same goes for Top
, Width
and Height
.
If I only set Left
the left side is placed correctly, but the moment I set Top
the previously value set to Left is now applied to the new scaling monitor and thus the left side also moves even though only Top
was updated.
My rather ugly, but working, solution is to loop through step 1 and 2 until the coordinates from Visual.PointFromScreen
no longer changes.
while (true)
{
var topLeft = PointFromScreen(new Point(o.Left, o.Top));
var bottomRight = PointFromScreen(new Point(o.Right, o.Bottom));
var x1 = Left + topLeft.X;
var y1 = Top + topLeft.Y;
var x2 = Left + bottomRight.X;
var y2 = Top + bottomRight.Y;
var w = x2 - x1;
var h = y2 - y1;
if (Left == x1 && Top == y1 && Width == w && Height == h)
break;
Left = x1;
Top = y1;
Width = w;
Height = h;
}
Are there any better ways, for example to set all location properties at once?
I want a WPF window to cover all monitors.
<Window ... WindowStyle="None" ...
In app.manifest
DPI Awareness is enabled:
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft/SMI/2016/WindowsSettings">PerMonitor</dpiAwareness>
<dpiAware xmlns="http://schemas.microsoft/SMI/2005/WindowsSettings">true</dpiAware>
<longPathAware xmlns="http://schemas.microsoft/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
The complete area covering all monitors is calculated by finding the outer limits of all Screen.AllScreens
.
Step 1: These screen coordinates are then translated to WPF coordinates using Visual.PointFromScreen
.
var topLeft = PointFromScreen(new Point(o.Left, o.Top));
var bottomRight = PointFromScreen(new Point(o.Right, o.Bottom));
var x1 = Left + topLeft.X;
var y1 = Top + topLeft.Y;
var x2 = Left + bottomRight.X;
var y2 = Top + bottomRight.Y;
var w = x2 - x1;
var h = y2 - y1;
Step 2: Finally the windows is positioned using the calculated coordinates.
Left = x1;
Top = y1;
Width = w;
Height = h;
However this fail with multiple monitors, each having separate DPI scaling.
Eventually I figured out that the output of Visual.PointFromScreen
changes with the monitor the window is located at.
The problem here is in step 2. After setting Left
the window has moved onto another monitor and a new set of coordinates need to be calculated using Visual.PointFromScreen
.
Same goes for Top
, Width
and Height
.
If I only set Left
the left side is placed correctly, but the moment I set Top
the previously value set to Left is now applied to the new scaling monitor and thus the left side also moves even though only Top
was updated.
My rather ugly, but working, solution is to loop through step 1 and 2 until the coordinates from Visual.PointFromScreen
no longer changes.
while (true)
{
var topLeft = PointFromScreen(new Point(o.Left, o.Top));
var bottomRight = PointFromScreen(new Point(o.Right, o.Bottom));
var x1 = Left + topLeft.X;
var y1 = Top + topLeft.Y;
var x2 = Left + bottomRight.X;
var y2 = Top + bottomRight.Y;
var w = x2 - x1;
var h = y2 - y1;
if (Left == x1 && Top == y1 && Width == w && Height == h)
break;
Left = x1;
Top = y1;
Width = w;
Height = h;
}
Are there any better ways, for example to set all location properties at once?
Share Improve this question asked Feb 13 at 20:12 hultqvisthultqvist 18.5k17 gold badges69 silver badges107 bronze badges1 Answer
Reset to default 1You can skip all these conversion by using SetWindowPos function.
using System.Runtime.InteropServices;
using System.Windows.Interop;
internal class Helper
{
[DllImport("User32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetWindowPos(
nint hWnd,
nint hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
uint uFlags);
public static bool SetWindowPosition(System.Windows.Window window, System.Drawing.Rectangle o)
{
nint handle = new WindowInteropHelper(window).EnsureHandle();
return SetWindowPos(handle, nint.Zero, o.Left, o.Top, o.Width, o.Height, 0);
}
}
本文标签: dpiWPF window covering all screens at the same timeStack Overflow
版权声明:本文标题:dpi - WPF window covering all screens at the same time - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741507508a2382408.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论