【发布时间】:2012-05-03 15:17:13
【问题描述】:
有没有办法确定打开的 WPF 窗口当前是否在任何桌面连接的监视器中可见?可见是指窗口的边界矩形与任何监视器的桌面矩形相交。
我需要此功能来确定是否需要重新定位窗口,因为监视器配置(工作区域边界、监视器计数)在我的应用程序重新启动(保存窗口位置)之间发生了变化。
我想出了下面的代码,它似乎可以工作,但它有几个问题:
- 我需要参考 windows 窗体。
- 我需要桌面的 DPI 设置并将窗口窗体实际像素转换为 WPF 虚拟像素。
- 我需要一个已经渲染的实际 Visual 实例来执行转换。
您知道解决上述三个问题的部分或全部的解决方案吗?
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
internal static class Desktop
{
private static Size dpiFactor = new Size(1.0, 1.0);
private static bool isInitialized;
public static IEnumerable<Rect> WorkingAreas
{
get
{
return
Screen.AllScreens.Select(
screen =>
new Rect(
screen.WorkingArea.Left * dpiFactor.Width,
screen.WorkingArea.Top * dpiFactor.Height,
screen.WorkingArea.Width * dpiFactor.Width,
screen.WorkingArea.Height * dpiFactor.Height));
}
}
public static void TryInitialize(Visual visual)
{
if (isInitialized)
{
return;
}
var ps = PresentationSource.FromVisual(visual);
if (ps == null)
{
return;
}
var ct = ps.CompositionTarget;
if (ct == null)
{
return;
}
var m = ct.TransformToDevice;
dpiFactor = new Size(m.M11, m.M22);
isInitialized = true;
}
}
(初始化的)Desktop 类的用法:
private bool IsLocationValid(Rect windowRectangle)
{
foreach (var workingArea in Desktop.WorkingAreas)
{
var intersection = Rect.Intersect(windowRectangle, workingArea);
var minVisible = new Size(10.0, 10.0);
if (intersection.Width >= minVisible.Width &&
intersection.Height >= minVisible.Height)
{
return true;
}
}
return false;
}
更新
使用虚拟屏幕 (SystemParameters.VirtualScreen*) 不起作用,因为当使用多个显示器时,“桌面”不是一个简单的矩形。它可能是一个多边形。虚拟屏幕会有盲点,因为
- 连接的屏幕可以有不同的分辨率
- 您可以配置每个屏幕的位置。
【问题讨论】:
-
尽管该链接中的问题非常相似,但它并没有回答我的问题。我已经提出了一个解决方案,我想找到一种方法来明确摆脱我提到的三个问题。
-
那么 WPF 和标准 C# 库无法帮助您。您可以尝试 PInvoke,但这可能更脏。有关更多信息,请参阅此问题:stackoverflow.com/questions/1927540/…
-
引用 System.Windows.Forms 有什么问题?这不像您要向垃圾箱添加另一个程序集。我个人的偏好是创建一个使用 PInvoke 的帮助器类,并保持代码干净可读。