【WPF】单双屏显示切换控制
前言
近期我完成了一个项目,该项目需求是在连接了双显示器的设备上,对屏幕显示设置的更改进行监听。具体而言,当显示设置调整为 “复制这些显示器” 时,程序要自动隐藏;而当显示设置变为 “扩展这些显示器” 时,程序则需显示在非主显示器的第二显示器上。接下来,我会对此次项目中的业务逻辑进行简单记录,希望能对你有所助益。
解决方案
启动程序时通过调用
ShowInSecondScreen2()
方法,将窗口移动至非主显示器上面。private double left = 0; private Rectangle primaryRect; private Rectangle secondRect; private double top = 0; private void ShowInSecondScreen2() { this.Dispatcher.Invoke(new Action(() => { this.WindowState = WindowState.Normal; //获取所有显示器的信息 Screen[] screens = Screen.AllScreens; //确定主显示器的分辨率,用于计算副显示器的起始位置 primaryRect = Screen.PrimaryScreen.Bounds; //将窗口放置在第一个找到的副显示器上 bool placed = false; foreach (Screen screen in screens) { if (screen.Primary == false) //找到的是非主显示器 { Rectangle workingArea = screen.Bounds; //设置窗口位置,使其在副显示器的左上角显示 left = this.Left = workingArea.Left; top = this.Top = workingArea.Top; this.Width = workingArea.Width; this.Height = workingArea.Height; secondRect = workingArea; placed = true; break; } } if (!placed) { // 如果没有找到副显示器,就在主显示器上显示 this.Left = primaryRect.Left; this.Top = primaryRect.Top; this.Width = secondRect.Width; this.Height = secondRect.Height; } this.Activate(); })); }
注册
SystemEvents.DisplaySettingsChanged
事件,用于监听屏幕显示设置的更改。private void MainWindow_Loaded(object sender, RoutedEventArgs e) { this.DataContext = (System.Windows.Application.Current.Resources["Locator"] as ViewModelLocator).Main; ShowInSecondScreen2(); Microsoft.Win32.SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged; }
编写
SystemEvents_DisplaySettingsChanged
事件方法,对单/双屏幕设置来控制窗口的显示位置。private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e) { try { var screens = System.Windows.Forms.Screen.AllScreens; if (screens.Length >= 2) { this.Show(); this.Dispatcher.Invoke(new Action(() => { this.Left = left; this.Top = top; this.Width = secondRect.Width; this.Height = secondRect.Height; this.Activate(); })); } else { this.Hide(); } } catch (Exception exp) { } }
注意
以上代码会受到系统缩放百分比影响,建议禁用DPI感知。在AssemblyInfo.cs
中,写入禁用DPI感知代码。
//禁用DPI感知
[assembly: System.Windows.Media.DisableDpiAwareness]
原因分析
DPI感知模式影响数据获取
默认情况下,未声明DPI感知的应用程序会被Windows自动进行位图缩放,导致
Screen.Bounds
返回逻辑分辨率而非物理分辨率。当主副显示器缩放比例不同时,
Screen
类可能仅返回主显示器缩放后的逻辑分辨率,而副显示器的物理分辨率无法正确识别。
Screen类的局限性
Screen.AllScreens
的Bounds
属性返回的是系统缩放后的逻辑分辨率,而非实际物理分辨率。在多显示器不同缩放比例场景下,未正确设置DPI感知的应用程序可能无法区分各显示器的实际分辨率。
- 感谢你赐予我前进的力量
赞赏者名单
因为你们的支持让我意识到写文章的价值🙏
评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果