在多屏显示系统中经常需要设置程序界面显示的屏幕位置,之前也曾写过控制屏幕位置的功能,偶然再一次使用中发现功能失效了,查了一下原因,这里对解决方案做一个简单的记录,以备备忘。
1.问题 “窗口启动位置 (WindowStartupLocation) 冲突”
首先说第一条:由于在设计程序时,一般会在主界面程序做默认设置窗体显示位置为屏幕中心位置,即 设置窗口的 WindowStartupLocation 设置为 CenterScreen 或 CenterOwner,后续手动设置 Left 和 Top 会被覆盖,导致设置失效。
- 解决方法
在构造函数中设置 WindowStartupLocationpublic MainWindow() {InitializeComponent();this.WindowStartupLocation = WindowStartupLocation.Manual; // 必须先设置Loaded += MainWindow_Loaded; }
2. 窗口状态 (WindowState) 冲突 (WindowStartupLocation) 冲突”
同上面类似,如果窗口处于最大化状态 (WindowState = Maximized),手动设置 Left 和 Top 无效
- 解决方法
在构造函数中设置 WindowsState,强制将窗口状态设为 Normalpublic MainWindow() {InitializeComponent();this.WindowStartupLocation = WindowStartupLocation.Manual; // 必须先设置this.WindowState=WindowState.Normal;//必须设置Loaded += MainWindow_Loaded; }
3. DPI 缩放问题”
问题:不同屏幕的 DPI 缩放比例不同,导致坐标计算错误。
- 解决方案:
将 System.Windows.Forms 获取的物理像素坐标转换为 WPF 的逻辑坐标。
在窗体显示位置设置方法中增加坐标转换private void setAppPostion() {// 获取所有屏幕Screen[] screens = Screen.AllScreens;// 假设要显示在第二个屏幕(索引从0开始)int targetScreenIndex = Int32.Parse(ConfigurationManager.AppSettings["screenIndex"]);if (targetScreenIndex < screens.Length){// 必须设置为Manual,手动指定位置this.WindowStartupLocation = WindowStartupLocation.Manual;Screen targetScreen = screens[targetScreenIndex];//获取当前窗口缩放比例var source = PresentationSource.FromVisual(this);if (source != null){Matrix transform = source.CompositionTarget.TransformFromDevice;double dipX = transform.M11;//水平缩放比例double dipY = transform.M22;//垂直缩放比例//将物理像素转换为逻辑单位this.Left = targetScreen.WorkingArea.Left / dipX;this.Top = targetScreen.WorkingArea.Top / dipY;//设置窗口大小为目标屏幕的工作区域尺寸this.Width = targetScreen.WorkingArea.Width;this.Height = targetScreen.WorkingArea.Height;}} }