【问题标题】:How can I get the active screen dimensions?如何获得活动屏幕尺寸?
【发布时间】:2008-10-31 16:55:12
【问题描述】:

我正在寻找的相当于窗口当前打开的监视器的System.Windows.SystemParameters.WorkArea

澄清:有问题的窗口是WPF,而不是WinForm

【问题讨论】:

  • 更改了接受的答案以反映 WPF 执行此操作的最佳方式。 System.Windows.SystemParameters.*
  • 对不使用 WinForms 命名空间的痴迷对我来说似乎很奇怪,它不会给你带来任何好处;相反,它使您没有正确解决问题所需的工具。
  • 对我来说,这与 WinForms 与 WPF 无关。这是关于学习新事物。如果我不学习两种方式,我无法决定哪种方式更好。
  • 嗯,在这种情况下,没有“两种方式”,因为只有一种方法可以做到这一点,那就是使用 WinForms 的东西。
  • @Jeff Yates:你是对的。我挖掘了我提出这个问题的原始项目,发现我使用了 PrimaryScreen* 属性。他们解决了我当天的需求,但没有解决我提出的实际问题。抱歉跑来跑去;我已经相应地更改了接受的答案。

标签: c# wpf


【解决方案1】:

Screen.FromControlScreen.FromPointScreen.FromRectangle 应该可以帮助您。例如在 WinForms 中是:

class MyForm : Form
{
  public Rectangle GetScreen()
  {
    return Screen.FromControl(this).Bounds;
  }
}

我不知道对 WPF 的等效调用。因此,您需要做类似这种扩展方法的事情。

static class ExtensionsForWPF
{
  public static System.Windows.Forms.Screen GetScreen(this Window window)
  {
    return System.Windows.Forms.Screen.FromHandle(new WindowInteropHelper(window).Handle);
  }
}

【讨论】:

  • 也许我的标记没有明确表明我使用的是 WPF 窗口,而不是 WinForms。我没有引用 System.Windows.Forms.dll,因为 WPF 有自己的继承树,所以它无论如何都不会工作。
  • 不客气。很抱歉没有直接得到答案 - 在我更新我的帖子之前,我必须调查 WPF 中可用的内容。
  • 这可以在右边放置一个窗口: var bounds = this.GetScreen().WorkingArea; this.Left = bounds.Right - this.Width;但它需要引用 System.Windows.Forms 和 System.Drawing,这并不理想。
  • @devios 请注意此调用不支持 DPI;您需要进行计算。
  • 在我的 VS 2015 WPF 应用程序中,在我的 Windows 10 Pro (v10.0.14393) 上的 4 显示器系统上以 .NET 4.5 为目标,并在显示器上使用 window高于我的 Primary (例如,它的 Top < 0),FromHandle 为我的主要监视器返回了 Screen(即使 window完全在辅助监视器中)!?!叹。看来我必须自己搜索 Screen.AllScreens 数组。为什么事情不能“正常工作”?!?哎呀。
【解决方案2】:

您可以使用它来获取主屏幕的桌面工作区边界:

System.Windows.SystemParameters.WorkArea

这对于获取主屏幕的大小也很有用:

System.Windows.SystemParameters.PrimaryScreenWidth System.Windows.SystemParameters.PrimaryScreenHeight

【讨论】:

  • 我很困惑...这似乎只是返回主屏幕尺寸。我想知道窗口当前所在屏幕的尺寸...
  • 这不能回答问题,即使您只想获取主显示器的大小,SystemParameters(在 WPF 中)也不正确。它们返回与设备无关的单位和 not 像素。要获得更好的实施,请参阅此答案:stackoverflow.com/questions/254197/…
  • PrimaryScreenHeight/Width 完全按预期工作,MSDN 上有以下内容:“获取一个指示主显示器的屏幕高度(以像素为单位)的值。” WorkArea 没有具体说像素,但文档和使用示例让我相信它也是像素。您是否有指向使用设备独立单元的链接?
【解决方案3】:

您可能还需要:

获取所有监视器的组合大小,而不是一个特定的监视器。

【讨论】:

  • 提示:要使用它,需要添加引用PresentationFramework.dllusing System.Windows;
【解决方案4】:

添加一个不使用 WinForms 而是使用 NativeMethods 的解决方案。 首先,您需要定义所需的本机方法。

public static class NativeMethods
{
    public const Int32 MONITOR_DEFAULTTOPRIMERTY = 0x00000001;
    public const Int32 MONITOR_DEFAULTTONEAREST = 0x00000002;


    [DllImport( "user32.dll" )]
    public static extern IntPtr MonitorFromWindow( IntPtr handle, Int32 flags );


    [DllImport( "user32.dll" )]
    public static extern Boolean GetMonitorInfo( IntPtr hMonitor, NativeMonitorInfo lpmi );


    [Serializable, StructLayout( LayoutKind.Sequential )]
    public struct NativeRectangle
    {
        public Int32 Left;
        public Int32 Top;
        public Int32 Right;
        public Int32 Bottom;


        public NativeRectangle( Int32 left, Int32 top, Int32 right, Int32 bottom )
        {
            this.Left = left;
            this.Top = top;
            this.Right = right;
            this.Bottom = bottom;
        }
    }


    [StructLayout( LayoutKind.Sequential, CharSet = CharSet.Auto )]
    public sealed class NativeMonitorInfo
    {
        public Int32 Size = Marshal.SizeOf( typeof( NativeMonitorInfo ) );
        public NativeRectangle Monitor;
        public NativeRectangle Work;
        public Int32 Flags;
    }
}

然后像这样获取监视器句柄和监视器信息。

        var hwnd = new WindowInteropHelper( this ).EnsureHandle();
        var monitor = NativeMethods.MonitorFromWindow( hwnd, NativeMethods.MONITOR_DEFAULTTONEAREST );

        if ( monitor != IntPtr.Zero )
        {
            var monitorInfo = new NativeMonitorInfo();
            NativeMethods.GetMonitorInfo( monitor, monitorInfo );

            var left = monitorInfo.Monitor.Left;
            var top = monitorInfo.Monitor.Top;
            var width = ( monitorInfo.Monitor.Right - monitorInfo.Monitor.Left );
            var height = ( monitorInfo.Monitor.Bottom - monitorInfo.Monitor.Top );
        }

【讨论】:

  • 如果你的窗口有比例因子(100% / 125% / 150% / 200%),你能得到真实的屏幕尺寸吗?
【解决方案5】:

添加到ffpf

Screen.FromControl(this).Bounds

【讨论】:

    【解决方案6】:

    注意窗口的比例因子(100% / 125% / 150% / 200%)。 您可以使用以下代码获取真实的屏幕尺寸:

    SystemParameters.FullPrimaryScreenHeight
    SystemParameters.FullPrimaryScreenWidth
    

    【讨论】:

    • 那是主屏幕 - 如果您的应用程序窗口位于虚拟(扩展)屏幕上(即您的 PC 上连接了一个或两个外部显示器)怎么办?
    【解决方案7】:

    我想在打开我的第一个窗口之前获得屏幕分辨率,所以这里有一个快速解决方案,可以在实际测量屏幕尺寸之前打开一个不可见的窗口(您需要调整窗口参数以适应您的窗口,以确保两者在同一屏幕上打开 - 主要是 WindowStartupLocation 很重要)

    Window w = new Window();
    w.ResizeMode = ResizeMode.NoResize;
    w.WindowState = WindowState.Normal;
    w.WindowStyle = WindowStyle.None;
    w.Background = Brushes.Transparent;
    w.Width = 0;
    w.Height = 0;
    w.AllowsTransparency = true;
    w.IsHitTestVisible = false;
    w.WindowStartupLocation = WindowStartupLocation.Manual;
    w.Show();
    Screen scr = Screen.FromHandle(new WindowInteropHelper(w).Handle);
    w.Close();
    

    【讨论】:

      【解决方案8】:

      这是一个“中心屏幕DotNet 4.5 solution”,使用SystemParameters 代替System.Windows.FormsMy.Compuer.Screen: 由于Windows 8 has changed 屏幕尺寸计算,它对我的​​唯一工作方式看起来像这样(包括任务栏计算):

      Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
          Dim BarWidth As Double = SystemParameters.VirtualScreenWidth - SystemParameters.WorkArea.Width
          Dim BarHeight As Double = SystemParameters.VirtualScreenHeight - SystemParameters.WorkArea.Height
          Me.Left = (SystemParameters.VirtualScreenWidth - Me.ActualWidth - BarWidth) / 2
          Me.Top = (SystemParameters.VirtualScreenHeight - Me.ActualHeight - BarHeight) / 2         
      End Sub
      

      【讨论】:

      • WPF 中的安装程序设置?
      • 主要问题是关于屏幕位置。像 Msi 安装程序、Innosetup 或其他安装程序一样,我创建了自己的安装程序,带有 CPU 检查、权限检查、驱动程序验证等等,非常易于使用。这就是截图。
      【解决方案9】:

      我需要设置我的窗口应用程序的最大大小。这可以相应地更改应用程序显示在主屏幕或辅助屏幕中。为了克服这个问题,我创建了一个简单的方法,接下来我将向您展示:

      /// <summary>
      /// Set the max size of the application window taking into account the current monitor
      /// </summary>
      public static void SetMaxSizeWindow(ioConnect _receiver)
      {
          Point absoluteScreenPos = _receiver.PointToScreen(Mouse.GetPosition(_receiver));
      
          if (System.Windows.SystemParameters.VirtualScreenLeft == System.Windows.SystemParameters.WorkArea.Left)
          {
              //Primary Monitor is on the Left
              if (absoluteScreenPos.X <= System.Windows.SystemParameters.PrimaryScreenWidth)
              {
                  //Primary monitor
                  _receiver.WindowApplication.MaxWidth = System.Windows.SystemParameters.WorkArea.Width;
                  _receiver.WindowApplication.MaxHeight = System.Windows.SystemParameters.WorkArea.Height;
              }
              else
              {
                  //Secondary monitor
                  _receiver.WindowApplication.MaxWidth = System.Windows.SystemParameters.VirtualScreenWidth - System.Windows.SystemParameters.WorkArea.Width;
                  _receiver.WindowApplication.MaxHeight = System.Windows.SystemParameters.VirtualScreenHeight;
              }
          }
      
          if (System.Windows.SystemParameters.VirtualScreenLeft < 0)
          {
              //Primary Monitor is on the Right
              if (absoluteScreenPos.X > 0)
              {
                  //Primary monitor
                  _receiver.WindowApplication.MaxWidth = System.Windows.SystemParameters.WorkArea.Width;
                  _receiver.WindowApplication.MaxHeight = System.Windows.SystemParameters.WorkArea.Height;
              }
              else
              {
                  //Secondary monitor
                  _receiver.WindowApplication.MaxWidth = System.Windows.SystemParameters.VirtualScreenWidth - System.Windows.SystemParameters.WorkArea.Width;
                  _receiver.WindowApplication.MaxHeight = System.Windows.SystemParameters.VirtualScreenHeight;
              }
          }
      }
      

      【讨论】:

      • 我的设置有 3 个监视器,“主要”和“次要”,因为唯一的选项会导致错误。
      【解决方案10】:

      在 C# winforms 中,借助以下方法,我得到了起点(例如,当我们有多个监视器/显示器并且一个表单正在调用另一个表单时):

      private Point get_start_point()
          {
              return
                  new Point(Screen.GetBounds(parent_class_with_form.ActiveForm).X,
                            Screen.GetBounds(parent_class_with_form.ActiveForm).Y
                            );
          }
      

      【讨论】:

        【解决方案11】:

        WinForms

        对于多显示器设置,您还需要考虑 X 和 Y 位置:

        Rectangle activeScreenDimensions = Screen.FromControl(this).Bounds;
        this.Size = new Size(activeScreenDimensions.Width + activeScreenDimensions.X, activeScreenDimensions.Height + activeScreenDimensions.Y);
        

        【讨论】:

          【解决方案12】:

          这个调试代码应该可以很好地解决问题:

          您可以探索Screen Class的属性

          使用 Screen.AllScreens 将所有显示放入数组或列表中,然后捕获当前显示的索引及其属性。

          C# (由 Telerik 从 VB 转换而来 - 请仔细检查)

                  {
              List<Screen> arrAvailableDisplays = new List<Screen>();
              List<string> arrDisplayNames = new List<string>();
          
              foreach (Screen Display in Screen.AllScreens)
              {
                  arrAvailableDisplays.Add(Display);
                  arrDisplayNames.Add(Display.DeviceName);
              }
          
              Screen scrCurrentDisplayInfo = Screen.FromControl(this);
              string strDeviceName = Screen.FromControl(this).DeviceName;
              int idxDevice = arrDisplayNames.IndexOf(strDeviceName);
          
              MessageBox.Show(this, "Number of Displays Found: " + arrAvailableDisplays.Count.ToString() + Constants.vbCrLf + "ID: " + idxDevice.ToString() + Constants.vbCrLf + "Device Name: " + scrCurrentDisplayInfo.DeviceName.ToString + Constants.vbCrLf + "Primary: " + scrCurrentDisplayInfo.Primary.ToString + Constants.vbCrLf + "Bounds: " + scrCurrentDisplayInfo.Bounds.ToString + Constants.vbCrLf + "Working Area: " + scrCurrentDisplayInfo.WorkingArea.ToString + Constants.vbCrLf + "Bits per Pixel: " + scrCurrentDisplayInfo.BitsPerPixel.ToString + Constants.vbCrLf + "Width: " + scrCurrentDisplayInfo.Bounds.Width.ToString + Constants.vbCrLf + "Height: " + scrCurrentDisplayInfo.Bounds.Height.ToString + Constants.vbCrLf + "Work Area Width: " + scrCurrentDisplayInfo.WorkingArea.Width.ToString + Constants.vbCrLf + "Work Area Height: " + scrCurrentDisplayInfo.WorkingArea.Height.ToString, "Current Info for Display '" + scrCurrentDisplayInfo.DeviceName.ToString + "' - ID: " + idxDevice.ToString(), MessageBoxButtons.OK, MessageBoxIcon.Information);
          }
          

          VB (原码)

           Dim arrAvailableDisplays As New List(Of Screen)()
              Dim arrDisplayNames As New List(Of String)()
          
              For Each Display As Screen In Screen.AllScreens
                  arrAvailableDisplays.Add(Display)
                  arrDisplayNames.Add(Display.DeviceName)
              Next
          
              Dim scrCurrentDisplayInfo As Screen = Screen.FromControl(Me)
              Dim strDeviceName As String = Screen.FromControl(Me).DeviceName
              Dim idxDevice As Integer = arrDisplayNames.IndexOf(strDeviceName)
          
              MessageBox.Show(Me,
                              "Number of Displays Found: " + arrAvailableDisplays.Count.ToString & vbCrLf &
                              "ID: " & idxDevice.ToString + vbCrLf &
                              "Device Name: " & scrCurrentDisplayInfo.DeviceName.ToString + vbCrLf &
                              "Primary: " & scrCurrentDisplayInfo.Primary.ToString + vbCrLf &
                              "Bounds: " & scrCurrentDisplayInfo.Bounds.ToString + vbCrLf &
                              "Working Area: " & scrCurrentDisplayInfo.WorkingArea.ToString + vbCrLf &
                              "Bits per Pixel: " & scrCurrentDisplayInfo.BitsPerPixel.ToString + vbCrLf &
                              "Width: " & scrCurrentDisplayInfo.Bounds.Width.ToString + vbCrLf &
                              "Height: " & scrCurrentDisplayInfo.Bounds.Height.ToString + vbCrLf &
                              "Work Area Width: " & scrCurrentDisplayInfo.WorkingArea.Width.ToString + vbCrLf &
                              "Work Area Height: " & scrCurrentDisplayInfo.WorkingArea.Height.ToString,
                              "Current Info for Display '" & scrCurrentDisplayInfo.DeviceName.ToString & "' - ID: " & idxDevice.ToString, MessageBoxButtons.OK, MessageBoxIcon.Information)
          

          【讨论】:

            【解决方案13】:

            我知道这是一个老问题,但其他人可能会从中获得一些价值

            int formWidth = form.Width;
            int formHeight = form.Height;
            int formTop = form.Top;
            int formLeft = form.Left;
            
            Screen screen = Screen.PrimaryScreen;
            Rectangle rect = screen.Bounds;
            int screenWidth = rect.Width;
            int screenHeight = rect.Height;
            int screenTop = rect.Top;
            int screenLeft = rect.Left;
            

            【讨论】:

              猜你喜欢
              • 2013-04-17
              • 2011-08-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-06-01
              • 1970-01-01
              • 2011-03-04
              相关资源
              最近更新 更多