这里有多个问题需要处理。
Resize
在调用之前(如果直接调用)Window
未完成 的 ,因此计算不正确。CenterWindow()
解决方案:CenterWindow()
从事件处理程序
中执行SizeChanged
并使用计时器来避免CenterWindow()
过于频繁地调用。
- 接下来,我们需要使用
this.ActualWidth
和this.ActualHeight
从事件处理程序中获取确切的尺寸,而不是this.Width
......
- 您的用户可能有多个屏幕(它们之间也有不同的分辨率)。当您执行
CenterWindow(...)
可用性时,在大多数情况下,您通常希望将当前屏幕居中而不是主要屏幕,而您的代码不会适应这种情况。
解决方案:
需要使用一些WinForms helper来获取实际屏幕,区分多个屏幕。
- 最后,WPF 尺寸与 DPI 无关,虽然应用上述步骤可以使其在默认 96dpi 下正常工作(win-8 也认为 win-7 和 vista),但当用户机器上的 dpi 不同时,您会开始看到奇怪的行为。
解决方案:
使用 dpi 独立措施来解决这个问题。
现在把这一切放在一起,我们得到类似的东西:
您需要参考System.Windows.Forms.dll
using System;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Windows.Media;
private readonly System.Timers.Timer _resizeTimer = new System.Timers.Timer(500);
public MainWindow() {
InitializeComponent();
...
SizeChanged += (sender, args) => {
_resizeTimer.Stop();
_resizeTimer.Start();
};
_resizeTimer.Elapsed +=
(sender, args) =>
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(CenterWindowToCurrentScreen));
}
public static double GetDpiFactor(Visual window) {
HwndSource windowHandleSource = PresentationSource.FromVisual(window) as HwndSource;
if (windowHandleSource != null && windowHandleSource.CompositionTarget != null) {
Matrix screenmatrix = windowHandleSource.CompositionTarget.TransformToDevice;
return screenmatrix.M11;
}
return 1;
}
private void CenterWindowToCurrentScreen() {
_resizeTimer.Stop();
double dpiFactor = GetDpiFactor(this);
var screen = Screen.FromHandle(new WindowInteropHelper(this).Handle);
double screenLeft = screen.Bounds.Left / dpiFactor;
double screenTop = screen.Bounds.Top / dpiFactor;
double screenWidth = screen.Bounds.Width / dpiFactor;
double screenHeight = screen.Bounds.Height / dpiFactor;
Left = ((screenWidth - ActualWidth) / 2) + screenLeft;
Top = ((screenHeight - ActualHeight) / 2) + screenTop;
}
笔记:
上述代码尚未适应的一件事是实际的任务栏尺寸。如果需要,您也可以从屏幕尺寸中减去它们以更加精确。