如何确定我的.NET Windows窗体程序在哪个显示器上运行?

58
我有一个C# Windows 应用程序,我希望确保它在用户将其移动到另一台显示器时会显示在第二个显示器上。我需要保存主窗体的大小、位置和窗口状态(这部分已处理好),但我还需要知道当用户关闭应用程序时它在哪个屏幕上运行。
我正在使用Screen类来确定当前屏幕的大小,但我找不到任何关于如何确定应用程序运行在哪个屏幕上的信息。
编辑:感谢大家的回复!我想确定窗口所在的监视器,以便在用户意外将窗口放在可视区域之外或更改屏幕大小以至于窗体不再完全可见时执行适当的范围检查。

如果这不是与https://dev59.com/n3NA5IYBdhLWcg3wgeAc类似的问题。 - sgmoore
5个回答

78

你可以使用以下代码来获取你拥有的屏幕数组。

Screen[] screens = Screen.AllScreens;

您可以通过运行以下代码(为所在的Windows窗体)来确定您所在的屏幕:

Screen screen = Screen.FromControl(this); //this is the Form class

简而言之,查看Screen类和静态帮助方法,它们可能会帮助您。

MSDN链接没有太多内容,我建议您自己在代码中尝试一下。


是的,人们似乎忘记了Form继承自Control,所以Screen.FromControl可以在其上工作。 - Powerlord
4
也许我应该重新表述一下…… Form 继承自 ContainerControl 类,ContainerControl 类又继承自 ScrollableControl 类,ScrollableControl 类再继承自 Control 类。 - Powerlord
1
@Janie:很抱歉你有这样的感受。我提供的代码确实做到了我所说的一切,没有多余的部分。如果你想要更深入地研究它,请跟随我提供的MSDN链接。 - Stan R.
@Janie:FromControl()方法返回一个Screen对象。你是不是认为它返回屏幕编号或者其他什么东西?你需要查询屏幕的Bounds来确定屏幕的位置。 - Tim
当运行您的应用程序时,请确保您的外部显示器未设置为“复制”。在此状态下调用Screen.AllScreens.Length将仅返回1(仅主屏幕)。 - Jer Yango
显示剩余2条评论

10

如果你记住了窗口的位置和大小,那就足够了。当你将位置设置为以前使用过的位置时,如果恰巧在第二个监视器上,它将返回那里。

例如,如果你有两个尺寸为1280x1024的显示器,并将窗口的左侧位置设置为2000px,则它将出现在第二个显示器上(假设第二个显示器在第一个显示器的右侧)。 :)

如果你担心下次启动应用程序时第二个显示器不在那里,你可以使用此方法确定窗口是否与任何屏幕相交:

private bool isWindowVisible(Rectangle rect)
{
    foreach (Screen screen in Screen.AllScreens)
    {
        if (screen.Bounds.IntersectsWith(rect))
            return true;
    }
    return false;
}

只需输入您的窗口所需位置,它会告诉您它是否可见于某个屏幕。享受吧!


1
同意,但在启动时进行一些检查会更好,这样在重新配置后,您的应用程序就不会超出所有监视器。 - H H
实际上,如果有人移除了第二个显示器,而您的应用程序尝试使用先前存在两个显示器时的顶部/左侧位置,Windows 将自动将其移动到第一个显示器。因此,实际上您不需要调用 isWindowVisible 方法。 - SolutionYogi
我同意Henk的观点 - 请查看我添加的示例,以便您可以检查您的窗口是否可见。 :) - Jon Tackabury
只是一个适用于使用.NET 3.5或更高版本的LINQy版本:return Screen.AllScreens.Any(s => s.Bounds.IntersectsWith(rect)); - MCattle

9
你可以使用以下代码获取当前屏幕:
var s = Screen.FromControl(this);

这里的this是指表单(Form)或表单上的任何控件。如何记住这一点有点棘手,但我会选择在Screen.AllScreens数组中使用索引,或者使用s.DeviceName。无论哪种情况,在启动时使用设置之前,请检查以防止使用已断开连接的监视器。


1
我不会选择使用DeviceName,因为DeviceName可能随时更改,比如当你获得一个新的显卡或显示器时... - Stan R.
我在Vista上得到它们的方式是\.\DISPLAY1和\.\DISPLAY2。但对于XP可能会有所不同,我不确定。 - H H
我同意,没有人真正确定...这就是为什么我不会使用它。 :) - Stan R.
DisplayName 看起来只是基于 Screen 认为屏幕的方式生成的值。在屏幕分辨率对话框中使用 identify 时,您会得到完全不同的屏幕 ID,与 nvidia 管理器相同,它显示与屏幕分辨率对话框相同的数字,但 .net 绝对必须做出不同的处理。 - neslekkiM

5

表单的位置将告诉您表单位于哪个屏幕上。我不是很理解为什么您需要知道它位于哪个屏幕上,因为如果您使用保存的位置还原它,它应该只会恢复到相同的位置(也许您可以进一步说明原因)。

否则,您可以执行以下操作:

Screen[] scr = Screen.AllScreens;
scr[i].Bounds.IntersectsWith(form.Bounds);

每个屏幕都有一个Bounds属性,返回一个矩形。您可以使用IntersectsWith()函数来确定窗体是否在屏幕内。
此外,它们基本上也提供了一个在Screen类上执行此操作的函数。
Screen screen = Screen.FromControl(form);

1
你可以使用'Screen'对象: System.Windows.Forms.Screen
从这里开始尝试一些东西:
        Screen[] screens = Screen.AllScreens;
        for (int i = 0; i < screens.Length ; i++)
        {
            Debug.Print(screens[i].Bounds.ToString());
            Debug.Print(screens[i].DeviceName);
            Debug.Print(screens[i].WorkingArea.ToString());
        }

这可能会给你所需的东西


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接