【问题标题】:C#: Get complete desktop size?C#:获得完整的桌面大小?
【发布时间】:2010-11-21 23:31:46
【问题描述】:

如何知道整个桌面的大小? 不是“工作区域”和不是“屏幕分辨率”,两者都只指一个屏幕。我想找出每台显示器只显示一部分的虚拟桌面的总宽度和高度。

【问题讨论】:

  • 也许“完整的桌面大小”取决于屏幕的定位方式。不知道如何计算,但您仍然可以使用 System.Windows.Forms.Screen.AllScreens 捕捉屏幕数量和每个屏幕的分辨率。

标签: c# .net desktop screen screen-resolution


【解决方案1】:

你有两个选择:

  1. PresentationFramework.dll

    SystemParameters.VirtualScreenWidth   
    SystemParameters.VirtualScreenHeight
    
  2. System.Windows.Forms.dll

    SystemInformation.VirtualScreen.Width   
    SystemInformation.VirtualScreen.Height
    

如果您开发 WPF 应用程序,请使用 第一个选项

【讨论】:

  • 更多这样的答案!简短、正确且美观!
  • 我发现如果启用缩放,这些值只会注册一个屏幕。可能取决于硬件,目前还不确定。
  • 这很可能是在 2011 年的时候考虑的,多桌面扩展并不是一件事。 @KellyElton 如果您找到修复程序,请更新答案。
  • 我无法找到解决方案,我认为这是一个错误。我正在使用 Blackweb BWA17HO002 usb3 到 hdmi 适配器,以及英特尔 HD 520(笔记本电脑)。当我在笔记本电脑上的显示比例 > 150% 时,这些值只会返回笔记本电脑的屏幕尺寸。一旦我删除了缩放,它就会注册第二个监视器。
【解决方案2】:

我认为是时候用一点 LINQ 来更新这个答案了,这样可以很容易地用一个表达式来获得整个桌面大小。

Console.WriteLine(
    Screen.AllScreens.Select(screen=>screen.Bounds)
    .Aggregate(Rectangle.Union)
    .Size
);

我的原始答案如下:


我猜你想要的是这样的:

int minx, miny, maxx, maxy;
minx = miny = int.MaxValue;
maxx = maxy = int.MinValue;

foreach(Screen screen in Screen.AllScreens){
    var bounds = screen.Bounds;
    minx = Math.Min(minx, bounds.X);
    miny = Math.Min(miny, bounds.Y);
    maxx = Math.Max(maxx, bounds.Right);
    maxy = Math.Max(maxy, bounds.Bottom);
}

Console.WriteLine("(width, height) = ({0}, {1})", maxx - minx, maxy - miny);

请记住,这并不能说明全部情况。多个显示器可以交错排列,或者排列成非矩形。因此,可能不是 (minx, miny) 和 (maxx, maxy) 之间的所有空间都是可见的。

编辑:

我刚刚意识到使用Rectangle.Union 的代码可能会更简单一些:

Rectangle rect = new Rectangle(int.MaxValue, int.MaxValue, int.MinValue, int.MinValue);

foreach(Screen screen in Screen.AllScreens)
    rect = Rectangle.Union(rect, screen.Bounds);

Console.WriteLine("(width, height) = ({0}, {1})", rect.Width, rect.Height);

【讨论】:

  • 我是乌克兰程序员。我正在验证此代码是否可以正常工作。只需复制和粘贴。
【解决方案3】:

检查:

SystemInformation.VirtualScreen.Width
SystemInformation.VirtualScreen.Height

【讨论】:

    【解决方案4】:

    要获得显示器的物理像素大小,您可以使用它。

    static class DisplayTools
    {
        [DllImport("gdi32.dll")]
        static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
    
        private enum DeviceCap
        {
            Desktopvertres = 117,
            Desktophorzres = 118
        }
    
        public static Size GetPhysicalDisplaySize()
        {
            Graphics g = Graphics.FromHwnd(IntPtr.Zero);
            IntPtr desktop = g.GetHdc();
    
            int physicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.Desktopvertres);
            int physicalScreenWidth = GetDeviceCaps(desktop, (int)DeviceCap.Desktophorzres);
    
            return new Size(physicalScreenWidth, physicalScreenHeight);
        }
    
    
    }
    

    【讨论】:

    • 这是第一个报告正确尺寸的,但仅适用于单个显示器。 ?
    【解决方案5】:

    这并不能回答问题,而只是增加了对所有屏幕中窗口点(位置)的额外洞察)。

    使用下面的代码来确定一个点(例如窗口的最后一个已知位置)是否在整个桌面的范围内。如果没有,请将窗口的位置重置为默认的 pBaseLoc;

    代码不考虑任务栏或其他工具栏,你自己在那里。

    示例使用:将 Window 位置从 station A 保存到数据库中。用户使用 2 台监视器登录 B 站,并将窗口移动到第二台监视器,注销并保存新位置。返回A站,除非使用上述代码,否则不会显示窗口。

    我的进一步解决方案是将用户 ID 和电台的 IP (&winLoc) 保存到数据库或给定应用程序的本地用户首选项文件,然后加载该电台和应用程序的用户首选项。

    Point pBaseLoc = new Point(40, 40)
    int x = -500, y = 140;
    Point pLoc = new Point(x, y);
    bool bIsInsideBounds = false;
    
    foreach (Screen s in Screen.AllScreens)
    {
        bIsInsideBounds = s.Bounds.Contains(pLoc);
        if (bIsInsideBounds) { break; }
    }//foreach (Screen s in Screen.AllScreens)
    
    if (!bIsInsideBounds) { pLoc = pBaseLoc;  }
    
    this.Location = pLoc;
    

    【讨论】:

    • 如果你知道这不能回答问题,你为什么要发布它作为问题的答案?第一句话不应该敲响警钟吗?
    • 另一方面,这正是我搜索该主题时所寻找的内容
    【解决方案6】:

    我认为获得“真实”屏幕尺寸的最佳方法是直接从视频控制器获取值。


        using System;
        using System.Management;
        using System.Windows.Forms;
    
        namespace MOS
        {
            public class ClassMOS
            {
                public static void Main()
                {
                    try
                    {
                        ManagementObjectSearcher searcher = 
                            new ManagementObjectSearcher("root\\CIMV2", 
                            "SELECT * FROM Win32_VideoController"); 
    
                        foreach (ManagementObject queryObj in searcher.Get())
                        {
                            Console.WriteLine("CurrentHorizontalResolution: {0}", queryObj["CurrentHorizontalResolution"]);
                            Console.WriteLine("-----------------------------------");
                            Console.WriteLine("CurrentVerticalResolution: {0}", queryObj["CurrentVerticalResolution"]);
                        }
                    }
                    catch (ManagementException e)
                    {
                        MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
                    }
                }
            }
    }
    

    这应该可以完成工作;) 问候...

    【讨论】:

      【解决方案7】:

      您可以使用System.Drawing 的边界。

      你可以创建这样的函数

      public System.Windows.Form.Screen[] GetScreens(){
          Screen[] screens = Screen.AllScreens;
          return screens;
      }
      

      你可以在这样的变量中获得屏幕一、二等:

      System.Windows.Form.Screen[] screens = func.GetScreens();
      System.Windows.Form.Screen screen1 = screens[0];
      

      那么你就可以得到屏幕的边界了:

      System.Drawing.Rectangle screen1Bounds = screen1.Bounds;
      

      使用此代码,您将获得 WidthHeight 等所有属性。

      【讨论】:

        【解决方案8】:

        此方法通过使用 Left 和 Top 的最小值以及 Right 和 Bottom 的最大值来返回包含所有屏幕边界的矩形...

        static Rectangle GetDesktopBounds() {
           var l = int.MaxValue;
           var t = int.MaxValue;
           var r = int.MinValue;
           var b = int.MinValue;
           foreach(var screen in Screen.AllScreens) {
              if(screen.Bounds.Left   < l) l = screen.Bounds.Left  ;
              if(screen.Bounds.Top    < t) t = screen.Bounds.Top   ;
              if(screen.Bounds.Right  > r) r = screen.Bounds.Right ;
              if(screen.Bounds.Bottom > b) b = screen.Bounds.Bottom;
           }
           return Rectangle.FromLTRB(l, t, r, b);
        }
        

        【讨论】:

        • 请解释一下。
        • 循环遍历所有屏幕。如果左边缘小于变量'l',它将'l'设置为这个新值,如果下边缘大于'b',则设置它。最终结果是 l、t、r、b 设置在整个可见桌面的左、上、右和下边缘。
        【解决方案9】:

        获取没有任何依赖关系的虚拟显示器的尺寸

        public enum SystemMetric
        {
            VirtualScreenWidth = 78, // CXVIRTUALSCREEN 0x0000004E 
            VirtualScreenHeight = 79, // CYVIRTUALSCREEN 0x0000004F 
        }
        
        [DllImport("user32.dll")]
        public static extern int GetSystemMetrics(SystemMetric metric);
        
        public static Size GetVirtualDisplaySize()
        {
            var width = GetSystemMetrics(SystemMetric.VirtualScreenWidth);
            var height = GetSystemMetrics(SystemMetric.VirtualScreenHeight);
        
            return new Size(width, height);
        }
        

        【讨论】:

        • 最佳答案 IMO,没有明确的依赖关系。
        【解决方案10】:

        来自 SM_XVIRTUALSCREEN 等的值是物理坐标,不等于控制面板中屏幕缩放 125%、150%、175% 时的逻辑坐标。

        【讨论】:

          【解决方案11】:

          您会发现许多窗口操作尚不可用或可能永远不可用。我在 PInvoke.User32 nuget 包方面取得了最大的成功。

          var screenX = PInvoke.User32.GetSystemMetrics(PInvoke.User32.SystemMetric.SM_CXSCREEN);
          var screenY = PInvoke.User32.GetSystemMetrics(PInvoke.User32.SystemMetric.SM_CYSCREEN);
          

          【讨论】:

            猜你喜欢
            • 2015-02-13
            • 1970-01-01
            • 1970-01-01
            • 2011-09-24
            • 1970-01-01
            • 2012-06-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多