恢复多个监视器的窗口大小/位置
许多帖子都涉及恢复 WinForm 位置和大小。
示例:
- www.stackoverflow.com/questions/92540/save-and-恢复形式位置和大小
- www.codeproject.com/KB/dialog/restoreposition.aspx?fid=1249382&df=90&mpp=25&noise=3& sort=Position&view=Quick&select=2595746
但我还没有找到代码来对多个显示器执行此操作。
也就是说,如果我关闭监视器 2 上窗口的 .NET Winform 应用程序,我希望它将窗口大小、位置和状态保存到应用程序设置中,以便稍后在我重新启动应用程序时恢复到监视器 2。 如果像上面的 codeproject 示例一样,它包含一些健全性检查,就像保存的位置大部分在屏幕外一样,它会“修复”它,那就太好了。 或者,如果保存的位置位于不再存在的显示器上(例如,我的笔记本电脑现在没有第二个显示器),那么它会正确地将其移动到显示器 1。
有什么想法吗?
我的环境:C#、.NET 3.5或以下、VS2008
Many posts around about restoring a WinForm position and size.
Examples:
- www.stackoverflow.com/questions/92540/save-and-restore-form-position-and-size
- www.codeproject.com/KB/dialog/restoreposition.aspx?fid=1249382&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2595746
But I have yet to find code to do this with multiple monitors.
That is, if I close my .NET Winform app with the window on monitor 2, I want it to save the windows size, location, and state to the application settings, so it could later restore to monitor 2 when I restart the app. It would be nice if, like in the codeproject example above, it includes some sanity checks, as in if the saved location is mostly off-screen it "fixes" it. Or if the saved location is on a monitor that is no longer there (e.g. my laptop is now by itself without my second monitor) then it correctly moves it to monitor 1.
Any thoughts?
My environment: C#, .NET 3.5 or below, VS2008
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
试试这个代码。 兴趣点:
边界和状态以其相应的类型存储在应用程序设置中,因此不需要进行任何字符串解析。 让框架发挥其序列化魔力。
参考设置文件:
Try this code. Points of interest:
The bounds and state are stored in the appsettings with their corresponding type so there's no need to do any string parsing. Let the framework do its serialization magic.
The settings file for reference:
VVS提供的答案很有帮助! 不过,我发现了两个小问题,因此我通过这些修订重新发布了他的大部分代码:
(1)应用程序第一次运行时,表单以正常状态打开,但其大小使其看起来就像标题栏。 我在构造函数中添加了一个条件来解决这个问题。
(2) 如果应用程序在最小化或最大化时关闭,则 OnClosing 中的代码无法记住正常状态下窗口的尺寸。 (这 3 行代码——我现在已经注释掉了——看起来很合理,但由于某种原因不起作用。)幸运的是,我之前已经解决了这个问题,并将该代码包含在代码末尾的新区域中跟踪窗口状态,而不是等待关闭。
完成这两个修复后,我测试了:
A. 以正常状态关闭 - 恢复到相同的尺寸/位置和状态
B. 以最小化状态关闭 - 以上次正常尺寸/位置恢复到正常状态
C. 以最大化关闭状态——恢复到最大化状态,并在稍后调整到正常状态时记住其最后的大小/位置。
D. 关闭监视器 2 - 恢复到监视器 2。
E. 关闭监视器 2 然后断开监视器 2 - 恢复到监视器 1 上的相同位置
David:你的代码让我几乎毫不费力地实现了 D 点和 E 点 - 不仅如此您是否为我的问题提供了解决方案?您在完整的程序中提供了它,因此我在将其粘贴到 Visual Studio 后几乎几秒钟内就启动并运行了它。 非常感谢!
The answer provided by VVS was a great help! I found two minor issues with it though, so I am reposting the bulk of his code with these revisions:
(1) The very first time the application runs, the form is opened in a Normal state but is sized such that it appears as just a title bar. I added a conditional in the constructor to fix this.
(2) If the application is closed while minimized or maximized the code in OnClosing fails to remember the dimensions of the window in its Normal state. (The 3 lines of code--which I have now commented out--seems reasonable but for some reason just does not work.) Fortunately I had previously solved this problem and have included that code in a new region at the end of the code to track window state as it happens rather than wait for closing.
With these two fixes in place, I have tested:
A. closing in normal state--restores to same size/position and state
B. closing in minimized state--restores to normal state with last normal size/position
C. closing in maximized state--restores to maximized state and remembers its last size/position when one later adjusts to normal state.
D. closing on monitor 2--restores to monitor 2.
E. closing on monitor 2 then disconnecting monitor 2--restores to same position on monitor 1
David: your code allowed me to achieve points D and E almost effortlessly--not only did you provide a solution for my question, you provided it in a complete program so I had it up and running almost within seconds of pasting it into Visual Studio. So a big thank you for that!
这里的大多数其他解决方案都依赖于手动确定每个显示器的当前位置。 边缘情况非常难以弄清楚,而且很少有应用程序能够自行解决问题。
Windows 本身中的 SetWindowPlacement 函数可以正确处理所有边缘情况 - 如果窗口位于可见屏幕之外,它会相应地进行调整。
我在 C# 中看到的最好的例子是 David Rickard 的博客。 它不仅展示了如何使用 SetWindowPlacement,还展示了如何序列化整个结果。
http: //blogs.msdn.com/b/davidrickard/archive/2010/03/09/ saving-window-size-and-location-in-wpf-and-winforms.aspx
Most of the other solutions here rely on manually figuring out the current positioning of each monitor. The edge cases are extremely difficult to figure out, and very few apps can get it right rolling their own.
The SetWindowPlacement function within Windows itself correctly handles all of the edge cases - if the window would be positioned off of a visible screen, it adjusts it accordingly.
The best example I've seen in C# is on David Rickard's blog. Not only does it show how to use SetWindowPlacement, it also shows how to serialize the entire result.
http://blogs.msdn.com/b/davidrickard/archive/2010/03/09/saving-window-size-and-location-in-wpf-and-winforms.aspx
根据您的回答和评论,我认为这是完美的。
此解决方案是使用多显示器 + 多文档、多表单或保存/恢复表单大小和位置 strong>多主窗体支持。 它不是MDI 形式,而是类似于Microsoft Word 的多文档,具有不同的主窗体实例。
感谢 VVS、msorens 和 Ian Goldby。 我合并了 VVS、msorens 和 MSDN Application.Run 方法 (ApplicationContext) 制作多 MainForm 但不是 MDI 的示例。
此修复包括 Ian Goldby 的评论,该评论使用
Form.RestoreBounds
消除OnResize()
、OnMove()
和TrackWindowState( )
。当表单移动到另一个监视器并在退出之前最大化时,我还修复了记住监视器,因为我没有跟踪 OnResize、OnMove。
通过此修复,此解决方案支持您需要的 Windows 7 Snap 功能可以拖动标题栏或 Win+箭头键将窗体窗口对齐到任何监视器边缘或使其最大化/正常以及最小化。
该解决方案在程序中实现,但不在主窗体中实现,以支持多主窗体。 但是,您也可以用于单个主表单。
编辑:添加 PreventSameLocation 方法以确保第二个表单打开不完全在第一个表单之上,并且用户会注意到新打开的表单。
This is the perfect one I think based on your answers and comments.
This solution is to save/restore form size and position with multi monitors + multi document, multi form or multi main form support. It is not MDI form but Microsoft Word like multi document with different main form instance.
Thanks to VVS, msorens and Ian Goldby. I merge the solution from VVS, msorens and MSDN Application.Run Method (ApplicationContext) example to make the multi MainForm but not MDI.
This fix of includes the comment from Ian Goldby which uses
Form.RestoreBounds
to eliminateOnResize()
,OnMove()
andTrackWindowState()
.I also fix to remember the Monitor when the Form move to the other Monitor and getting maximized before exit because I not tracking the OnResize, OnMove.
By this fix, this solution support Windows 7 Snap feature which you can drag the titlebar or Win+Arrow key to snap Form window into any monitor edge or make it maximized/normal as well as minimized.
This solution implemented in Program but not in the main Form to support multi main Form. However you can use for single main Form also.
Edit: PreventSameLocation method added to make sure the 2nd form opened not exactly on top of the 1st form and user will notice the newly opened form.
如果您有多个显示器,我相信屏幕 UI 尺寸会更大。 因此,存储和恢复位置的正常“1 监视器”方法就可以工作。 我没有尝试过这个,因为我远离我的第二台显示器,但测试应该不难。 你问问题的方式似乎你还没有测试过。
您的第二个要求意味着您必须在恢复应用程序时检查最大屏幕尺寸,然后根据需要重新定位。 为了完成后一点,我使用以下代码:
我在恢复表单时调用此方法。 我在窗体关闭时将屏幕几何形状存储在注册表中,然后在窗体打开时读取几何形状。 我得到了边界,但随后使用上面的方法将恢复的边界限制到实际的当前屏幕。
关闭时保存:
打开表单时恢复:
If you have multiple monitors, I believe the screen UI dimensions are simply larger. So the normal "1 monitor" approach of storing and restoring the location will just work. I haven't tried this because I am away from my second monitor but it shouldn't be hard to test. The way you asked the Question is seems like you haven't tested it.
Your second requirement will mean you will have to check the max sceen dimensions when restoring the app, and then reposition as necessary. To do this latter bit, I use this code:
I call this method when restoring the form. I store the screen geometry in the registry on form close, and then read the geometry on form open. I get the bounds, but then constrain the restored bounds to the actual current screen, using the method above.
Save on close:
Restore on form open:
这是一个老问题,但这里是基于之前答案的 VB 版本。
VVS 和 Michael Sorens 提出的答案存在一个问题,即仅在屏幕上显示几个像素的已保存位置算作可见。 在恢复之前的位置之前,此解决方案需要至少 50x50 像素的交集。
设置:
表格:
This is an old question, but here is a VB version based on the previous answers.
One problem with the answers suggested by VVS and Michael Sorens is that a saved position that only shows a couple of pixels on a screen counts as visible. This solution requires at least 50x50 pixels in intersection before restoring the previous location.
Settings:
Form: