¿Cómo puedo obtener las dimensiones de la pantalla activa?

142

Lo que estoy buscando es el equivalente del System.Windows.SystemParameters.WorkAreamonitor en el que se encuentra actualmente la ventana.

Aclaración: la ventana en cuestión es WPF, no WinForm.

frío
fuente
2
Se cambió la respuesta aceptada para reflejar la mejor manera de hacer esto desde WPF. System.Windows.SystemParameters. *
chilltemp
1
La obsesión por no usar un espacio de nombres WinForms me parece extraña, no te gana nada; en cambio, te deja sin las herramientas que necesitas para resolver adecuadamente el problema.
Jeff Yates
44
Para mí, no se trata de WinForms vs.WPF. Se trata de aprender algo nuevo. No puedo decidir qué camino es mejor si no aprendo los dos.
chilltemp
3
Bueno, en este escenario no hay "ambas formas", ya que solo hay una manera de hacer esto, que es usar las cosas de WinForms.
Jeff Yates
@ Jeff Yates: Tienes razón. Desenterré el proyecto original para el que hice esta pregunta y descubrí que usaba las propiedades de PrimaryScreen *. Resolvieron mis necesidades del día, pero no la pregunta real que hice. Perdón por la vuelta; He cambiado la respuesta aceptada en consecuencia.
chilltemp

Respuestas:

143

Screen.FromControl, Screen.FromPointy Screen.FromRectangledebería ayudarte con esto. Por ejemplo en WinForms sería:

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

No sé de una llamada equivalente para WPF. Por lo tanto, debe hacer algo como este método de extensión.

static class ExtensionsForWPF
{
  public static System.Windows.Forms.Screen GetScreen(this Window window)
  {
    return System.Windows.Forms.Screen.FromHandle(new WindowInteropHelper(window).Handle);
  }
}
Jeff Yates
fuente
1
Quizás mi etiquetado no dejó en claro que estoy usando ventanas WPF, no WinForms. No tengo el System.Windows.Forms.dll referenciado, y no funcionaría de todos modos ya que WPF tiene su propio árbol de herencia.
chilltemp
1
De nada. Mis disculpas por no llegar directamente a la respuesta: tuve que investigar lo que estaba disponible en WPF antes de actualizar mi publicación.
Jeff Yates el
Esto funciona para poner una ventana en el borde derecho: var limits = this.GetScreen (). WorkingArea; this.Left = limits.Right - this.Width; Pero requiere referencias a System.Windows.Forms y System.Drawing, lo cual no es ideal.
Anthony
1
@devios Tenga en cuenta que esta llamada no es compatible con DPI; Necesitarás hacer cálculos.
Lynn Desmoronando el
66
En mi aplicación VS 2015 WPF dirigida a .NET 4.5 en mi sistema de 4 monitores en Windows 10 Pro (v10.0.14393) con windowel monitor encima de mi primario (por ejemplo, su Top < 0), FromHandledevolvió el Screenpara mi monitor primario (aunque windowestaba completamente dentro el monitor secundario) Suspiro. Parece que tendré que buscar la Screen.AllScreensmatriz yo mismo. ¿Por qué las cosas no pueden "simplemente funcionar"? Arrrrgh.
Tom
62

Puede usar esto para obtener los límites del espacio de trabajo de la pantalla principal:

System.Windows.SystemParameters.WorkArea

Esto también es útil para obtener solo el tamaño de la pantalla principal:

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

Pyttroll
fuente
19
Estoy confundido ... Esto solo parece devolver las dimensiones de la pantalla principal. Quiero saber las dimensiones de la pantalla en la que se encuentra actualmente la ventana ...
VitalyB
1
esto no responde la pregunta e incluso si solo desea obtener el tamaño de la pantalla principal, los Parámetros del sistema (en WPF) son incorrectos. devuelven unidades independientes del dispositivo y no píxeles. para una mejor implementación, vea esta respuesta: stackoverflow.com/questions/254197/…
Patrick Klug
1
PrimaryScreenHeight / Width funcionó exactamente como se esperaba, y MSDN tiene lo siguiente: "Obtiene un valor que indica la altura de la pantalla, en píxeles, del monitor de visualización principal". WorkArea no dice específicamente píxeles, pero la documentación y los ejemplos de uso me llevan a creer que también está en píxeles. ¿Tiene un enlace a algo que indique el uso de unidades independientes del dispositivo?
chilltemp
17

Agregar una solución que no usa WinForms sino NativeMethods. Primero debe definir los métodos nativos necesarios.

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;
    }
}

Y luego obtenga el asa del monitor y la información del monitor como esta.

        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 );
        }
R.Rusev
fuente
1
¿Puede obtener el tamaño de pantalla real si hay un factor de escala de sus ventanas (100% / 125% / 150% / 200%)?
Kiquenet
12

Agregar a ffpf

Screen.FromControl(this).Bounds
defectuoso
fuente
12

Tenga cuidado con el factor de escala de sus ventanas (100% / 125% / 150% / 200%). Puede obtener el tamaño de pantalla real utilizando el siguiente código:

SystemParameters.FullPrimaryScreenHeight
SystemParameters.FullPrimaryScreenWidth
aDoubleSo
fuente
1
Eso es para la pantalla principal: ¿qué sucede si la ventana de su aplicación está en una pantalla virtual (extendida) (es decir, tiene uno o dos monitores externos conectados a su PC)?
Matt
4

Quería tener la resolución de la pantalla antes de abrir la primera de mis ventanas, así que aquí una solución rápida para abrir una ventana invisible antes de medir realmente las dimensiones de la pantalla (debe adaptar los parámetros de la ventana a su ventana para asegurarse de que ambas estén abiertas la misma pantalla, principalmente WindowStartupLocationes importante)

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();
Andre
fuente
3

Esta es una " solución Center Screen DotNet 4.5 ", que utiliza SystemParameters en lugar de System.Windows.Forms o My.Compuer.Screen : dado que Windows 8 ha cambiado el cálculo de la dimensión de la pantalla, la única forma en que funciona para mí es así (cálculo de la barra de tareas incluido):

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

Pantalla central WPF XAML

Nasenbaer
fuente
instalación del instalador en WPF?
Kiquenet
La pregunta principal es sobre la posición de la pantalla. Al igual que el instalador Msi, Innosetup u otros, creé mi propio instalador con verificación de CPU, verificación de permisos, verificación de controladores y mucho más, muy simple de usar. Esa es la captura de pantalla sobre.
Nasenbaer
3

Necesitaba establecer el tamaño máximo de mi aplicación de ventana. Este podría cambiar en consecuencia, la aplicación se muestra en la pantalla principal o en la secundaria. Para superar este problema, creé un método simple que le muestro a continuación:

/// <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;
        }
    }
}
Ricardo Magalhães
fuente
1

en C # winforms tengo un punto de inicio (para el caso cuando tenemos varios monitores / diplay y un formulario llama a otro) con la ayuda del siguiente método:

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

WinForms

Para configuraciones de monitores múltiples también necesitará tener en cuenta la posición X e Y:

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

Este código de depuración debería funcionar bien:

Puede explorar las propiedades de la clase de pantalla

Coloque todas las pantallas en una matriz o lista usando Screen.AllScreens y luego capture el índice de la pantalla actual y sus propiedades.

ingrese la descripción de la imagen aquí

C # (Convertido de VB por Telerik - Por favor verifique dos veces)

        {
    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 (código original)

 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)

Lista de pantallas

Daniel Santos
fuente