解决使用多个屏幕时, v2rayN 窗口大于当前窗口的问题 获取窗口所在当前屏幕 WPF 与 WinForms 共存
需求
上一篇的需求 "设置窗口的尺寸, 不要超过当前屏幕" 其实并没有解决得很完满.
在上一篇中, 只解决了使用一个屏幕的情况. 虽然从使用的单词来看, 似乎
解决思路
获取程序运行所在当前屏幕, 根据屏幕的尺寸, 位置和
具体实践
安装 Microsoft Visual Studio
在 Microsoft Store 里有
安装组件选 .NET 桌面开发
下载源码
修改源码
打开 .sln 文件.
引入 WinForms (System.Windows.Forms)
我搜索了很多, 在使用多个屏幕时, 在纯
在项目.proj
解决引入 WinForms 后的编译问题
双击编译的错误提示, 打开代码文件以后, 把下面这一段直接增加到文件的头部.
using Application = System.Windows.Application;using Clipboard = System.Windows.Clipboard;using DataFormats = System.Windows.DataFormats;using DataObject = System.Windows.DataObject;using DragDropEffects = System.Windows.DragDropEffects;using DragEventArgs = System.Windows.DragEventArgs;using FontFamily = System.Windows.Media.FontFamily;using IDataObject = System.Windows.IDataObject;using KeyEventArgs = System.Windows.Input.KeyEventArgs;using MessageBox = System.Windows.MessageBox;using MouseEventArgs = System.Windows.Input.MouseEventArgs;using OpenFileDialog = Microsoft.Win32.OpenFileDialog;using Point = System.Windows.Point;using SaveFileDialog = Microsoft.Win32.SaveFileDialog;using TextBox = System.Windows.Controls.TextBox;using UserControl = System.Windows.Controls.UserControl;
不断的编译, 报错, 打开报错的文件, 把这一大段声明丢进去, 再编译... 最终就会全部编译通过了.
在窗口的 Windows_Loaded 函数中修改窗口属性
修改窗口尺寸不能在构造函数中进行, 因为获取不到
在所有的窗口代码文件里找
比如, 绿色部分是新增的.
如果窗口代码文件没有
在 Owner 后面添加一行
this.Loaded += Window_Loaded;
再利用智能提示的功能, 生成方法"Window_Loaded".
自动帮你生成了函数的架子. 把内容删掉, 填写我们自己的.
// 获取屏幕的 DPI 缩放因素double dpiFactor = 1;PresentationSource source = PresentationSource.FromVisual(this);if (source != null){dpiFactor = source.CompositionTarget.TransformToDevice.M11;}// 获取当前屏幕的尺寸var screen = System.Windows.Forms.Screen.FromHandle(new System.Windows.Interop.WindowInteropHelper(this).Handle);var screenWidth = screen.WorkingArea.Width / dpiFactor;var screenHeight = screen.WorkingArea.Height / dpiFactor;var screenTop = screen.WorkingArea.Top / dpiFactor;var screenLeft = screen.WorkingArea.Left / dpiFactor;var screenBottom = screen.WorkingArea.Bottom / dpiFactor;var screenRight = screen.WorkingArea.Right / dpiFactor;// 设置窗口尺寸不超过当前屏幕的尺寸if (this.Width > screenWidth){this.Width = screenWidth;}if (this.Height > screenHeight){this.Height = screenHeight;}// 设置窗口不要显示在屏幕外面if (this.Top < screenTop){this.Top = screenTop;}if (this.Left < screenLeft){this.Left = screenLeft;}if (this.Top + this.Height > screenBottom){this.Top = screenBottom - this.Height;}if (this.Left + this.Width > screenRight){this.Left = screenRight - this.Width;}
保存, 编译, 开始调试
用菜单也可以, 用快捷键也可以, 用快捷按钮也可以.
解决过程
我问
代码搬过来.
编译的时候报错.
错误 CS0234 命名空间“System.Windows” 中不存在类型或命名空间名 “Forms”(是否缺少程序集引用?) v2rayN D:\_work\v2rayN-master1\v2rayN\v2rayN\Views\AddServerWindow.xaml.cs 177
我试过在代码顶部声明
但是编译还是不行.
错误 CS0234 命名空间“System.Windows” 中不存在类型或命名空间名 “Forms”(是否缺少程序集引用?) v2rayN D:\_work\v2rayN-master1\v2rayN\v2rayN\Views\AddServerWindow.xaml.cs 10
而且它还说, 在
我换了好多种表达方法去问
后来我发现这其实是一个突破口, 我经过
但是打开这个设置以后, 编译的时候就冒出来好多错误.
有一点编程基础的人看了就明白, 肯定是在
双击错误, 跳转到报错的地方. 有一个给你提示如何修改的功能.
点击这个按钮也行, 使用快捷键也行, 使用这个功能. 选下面这一项.
因为:
首先, 这是在项目中引用
其次, 写成
不断地在每一个这样的报错的地方, 选择
这个声明反正写得多, 没用到是没毛病的. 所以我趟过了一遍坑之后, 给你一个简单粗暴的方法 ---- 你双击错误提示打开代码文件以后, 把下面这一段直接增加到文件的头部.
using Application = System.Windows.Application;using Clipboard = System.Windows.Clipboard;using DataFormats = System.Windows.DataFormats;using DataObject = System.Windows.DataObject;using DragDropEffects = System.Windows.DragDropEffects;using DragEventArgs = System.Windows.DragEventArgs;using FontFamily = System.Windows.Media.FontFamily;using IDataObject = System.Windows.IDataObject;using KeyEventArgs = System.Windows.Input.KeyEventArgs;using MessageBox = System.Windows.MessageBox;using MouseEventArgs = System.Windows.Input.MouseEventArgs;using OpenFileDialog = Microsoft.Win32.OpenFileDialog;using Point = System.Windows.Point;using SaveFileDialog = Microsoft.Win32.SaveFileDialog;using TextBox = System.Windows.Controls.TextBox;using UserControl = System.Windows.Controls.UserControl;
不断的编译, 报错, 把这一大段声明丢进去, 再编译... 最终就会全部编译通过了.
运行起来看看效果? 不行.
鼠标在这个位置点一下, 在代码中设置一个断点
再次使用添加服务器功能, 唤出窗口. 可以看到程序暂停在这里. 注意观察正文的局部变量窗口. 可以看到变量 screenWidth 的值 为
如果你手里有上一篇的方案实施效果成功的调试环境, 你也可以在类似的位置设置断点. 但是默认没有显示 this.MaxWidth 和 this.MaxHeight 的值.
当然鼠标移上去, 会有显示, 但是如果长期调试工作, 还是在窗口有显示这些你关心的变量的值比较好.
在下图中箭头所指的地方鼠标右键, 菜单中选择"添加监视".
把
去问
不能完全照抄, 稍微阅读一下. 写到代码里这样子:
再编译, 执行, 测试一下. 嗯. 又出现了窗口下边框"缩起来"了的情况.
(我的测试环境是一个大屏幕, 一个小屏幕. 大屏幕为主屏幕. 小屏幕
还是在代码里去看断点暂停时的各个变量. 发现很奇怪的, 窗口的左上角都在屏幕外面了, 但是
再结合我的两个屏幕的环境思考.
这个窗口应该是下面这么个情况, 所以 top 属性不是负数.
这样的话, 我们要得到那个屏幕的
代码改成这样:
// 设置窗口不要显示在屏幕外面if (this.Top < screenTop / dpiFactor){this.Top = screenTop / dpiFactor;}
再测试. 嗯, 没问题了!
实施到每一个窗口
在所有的
这里面不是每个文件里都有
比如, DNS
找到初始化函数
在 Owner 后面添加一行
this.Loaded += Window_Loaded;
再利用智能提示的功能, 生成方法"Window_Loaded".
自动帮你生成了函数的架子. 把内容删掉, 填写我们自己的.
这里也许你会问, 为什么不能像上一篇方案中那样写到初始化函数
好, 我们以主窗口为例, 看一下写到构造函数里是什么效果.
主窗口是这个:
我们做如此修改:
编译生成的可执行文件在这个位置
v2rayN-master1\v2rayN\v2rayN\bin\Debug\net6.0-windows
执行. 乍一看挺好. 但, 如果我们把窗口拖到大屏幕上把尺寸拉高, 然后关闭, 然后在小屏幕的文件管理器上打开可执行文件, 你会发现窗口高度超过屏幕了.
我们的代码没起作用吗? 在代码中打断点, 看看究竟.
发现, 获取窗口的
看来在窗口显示出来之前, 是获取不到
问
编译, 执行, 测试. 发现, 在小屏幕生成的窗口, 拖到大屏幕上, 想显示多一点内容, 拖窗口边框拖不动, 窗口最大化但还是只显示那么一点内容.
原因是我们指定了窗口尺寸的最大值.
修改为, 调整窗口当前尺寸不超过屏幕.
// 设置窗口尺寸不超过当前屏幕的尺寸if (this.Width > screenWidth / dpiFactor){this.Width = screenWidth / dpiFactor;}if (this.Height > screenHeight / dpiFactor){this.Height = screenHeight / dpiFactor;}
再构造不同的大小屏幕之间的位置关系测试.
把小屏幕设置为主屏幕, 把窗口拖到大屏幕上调整为大尺寸, 再退出程序. 然后在小屏幕上打开, 这样程序会在小屏幕上显示.
发现只判断了窗口的
所以应该要判断窗口的整个区域都要在屏幕的范围内.
假设我们对窗口相关的知识一无所知, 去问
学习关键逻辑, 代码改成这样:
// 获取屏幕的 DPI 缩放因素double dpiFactor = 1;PresentationSource source = PresentationSource.FromVisual(this);if (source != null){dpiFactor = source.CompositionTarget.TransformToDevice.M11;}// 获取当前屏幕的尺寸var screen = System.Windows.Forms.Screen.FromHandle(new System.Windows.Interop.WindowInteropHelper(this).Handle);var screenWidth = screen.WorkingArea.Width / dpiFactor;var screenHeight = screen.WorkingArea.Height / dpiFactor;var screenTop = screen.WorkingArea.Top / dpiFactor;var screenLeft = screen.WorkingArea.Left / dpiFactor;var screenBottom = screen.WorkingArea.Bottom / dpiFactor;var screenRight = screen.WorkingArea.Right / dpiFactor;// 设置窗口尺寸不超过当前屏幕的尺寸if (this.Width > screenWidth){this.Width = screenWidth;}if (this.Height > screenHeight){this.Height = screenHeight;}// 设置窗口不要显示在屏幕外面if (this.Top < screenTop){this.Top = screenTop;}if (this.Left < screenLeft){this.Left = screenLeft;}if (this.Top + this.Height > screenBottom){this.Top = screenBottom - this.Height;}if (this.Left + this.Width > screenRight){this.Left = screenRight - this.Width;}
编译, 执行, 测试. 看起来一切正常了.
评论
发表评论