屏幕分辨率与Screen.Bounds不匹配

时间:2015-01-16 15:17:08

标签: c# windows-8.1 resolution dpi

我看到通过控制面板设置的分辨率与我的宽屏笔记本电脑的Screen.Bounds输出之间存在一个有趣的区别。屏幕为15.5“,通过控制面板设置的分辨率为1920x1080。但是当我运行这样的代码时。

Screen[] screens = Screen.AllScreens;
foreach (Screen scr in screens)
{
    Console.WriteLine("Width: " + scr.Bounds.Width + ", Height: " + scr.Bounds.Width);
}

输出显示我的分辨率为1536x864。我做了一些环顾四周,我认为它可能与DPI问题有关,当我查看我的显示设置时,滑块(我在Windows 8.1上)位于中间,复选框指出“让我为我的所有显示选择一个缩放级别“未选中。我运行这个小代码来获取当前的DPI设置。

float dpiX, dpiY;
Graphics graphics = new System.Windows.Forms.Form().CreateGraphics();
Console.WriteLine("DPI: " + graphics.DpiX);

返回的DPI是96.0,根据我的理解,这是100%DPI设置(因此没有放大或任何调用)。对我来说似乎很奇怪的是,Screen返回的界限恰好是我实际分辨率的80%,这会让我认为我的DPI设置为100(或125%),但事实并非如此。我的笔记本电脑屏幕只有这个问题,因为我的辅助显示器的界限等于通过控制面板的分辨率。这是因为我的DPI设置未设置为使显示器彼此独立(选中该复选框)?对于一些背景知识,我正在编写一个工具,它可以获取当前屏幕并从reddit获取图片并将它们彼此独立地放到屏幕上,所以无论我有什么解决方案,它都必须正确地获得每个显示器的分辨率。

2 个答案:

答案 0 :(得分:10)

我对屏幕截图工具也有同样的问题。 我找到了解决方案,它对我有用。

private enum ProcessDPIAwareness
{
  ProcessDPIUnaware = 0,
  ProcessSystemDPIAware = 1,
  ProcessPerMonitorDPIAware = 2
}

[DllImport("shcore.dll")]
private static extern int SetProcessDpiAwareness(ProcessDPIAwareness value);

private static void SetDpiAwareness()
{
  try
  {
    if (Environment.OSVersion.Version.Major >= 6)
    {
      SetProcessDpiAwareness(ProcessDPIAwareness.ProcessPerMonitorDPIAware);
    }
  }
  catch (EntryPointNotFoundException)//this exception occures if OS does not implement this API, just ignore it.
  {
  }
}

你应该在调用函数之前调用SetDpiAwareness()方法来获得系统解析等。 此外,如果您的应用程序中有一些UI,则您有责任在具有高DPI的屏幕中扩展UI。

希望这有帮助。

答案 1 :(得分:4)

我相信您必须通知操作系统您的应用程序可识别DPI。否则操作系统假装一切都很好,导致你正在观察的行为 - 操作系统处理调整大小。

您可以在此处找到有关编写DPI感知应用程序的一些信息 - http://msdn.microsoft.com/cs-cz/library/dd464646.aspx当然,您应该确保您的应用程序实际 DPI意识到 - 如果没有,您最好坚持默认。它不是很好,但至少它会起作用。

Windows 8.1带来的主要区别在于您可以在不同的监视器上使用不同的DPI,并且可以查询监视器DPI API。默认情况下,.NET(尤其是WPF)会自动处理DPI感知,但仅基于系统DPI。如果您的显示器具有不同的DPI设置,它将表现为非DPI感知(更确切地说,系统DPI感知,但最终结果是您的应用程序图形将由Windows虚拟化)。我希望如果您断开第二个显示器,您的应用程序将在您的唯一显示器上按预期运行(至少在手动设置DPI后,无论价值如何)。