¿Cómo obtener el tamaño de la pantalla actual en WPF?

87

Sé que puedo obtener el tamaño de la pantalla principal usando

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

Pero, ¿cómo obtengo el tamaño de la pantalla actual? (Los usuarios de pantallas múltiples no siempre usan la pantalla principal y no todas las pantallas usan la misma resolución, ¿verdad?)

Sería bueno poder acceder al tamaño desde XAML, pero hacerlo desde el código (C #) sería suficiente.

Nils
fuente
1
Defina "actual". Una ventana puede estar en más de una pantalla a la vez.
Jim Balter

Respuestas:

13

Hasta donde yo sé, no existe una función WPF nativa para obtener las dimensiones del monitor actual. En su lugar, podría PInvoke funciones nativas de varios monitores de pantalla , envolverlas en una clase administrada y exponer todas las propiedades que necesita para consumirlas desde XAML.

Anvaka
fuente
Eso es exactamente lo que temía: la necesidad de P / Invocar las cosas o acceder a System.Windows.Forms.Screen de alguna manera. Y al hacerlo, siempre necesito calcular los "píxeles independientes del dispositivo" ... Aunque gracias.
Nils
Sí ... Quizás la función SystemParameters.ConvertPixel () también lo ayude. Es interno, pero a Reflector no le importa
:)
74

Creé un pequeño envoltorio alrededor de la pantalla de System.Windows.Forms, actualmente todo funciona ... Aunque no estoy seguro acerca de los "píxeles independientes del dispositivo".

public class WpfScreen
{
    public static IEnumerable<WpfScreen> AllScreens()
    {
        foreach (Screen screen in System.Windows.Forms.Screen.AllScreens)
        {
            yield return new WpfScreen(screen);
        }
    }

    public static WpfScreen GetScreenFrom(Window window)
    {
        WindowInteropHelper windowInteropHelper = new WindowInteropHelper(window);
        Screen screen = System.Windows.Forms.Screen.FromHandle(windowInteropHelper.Handle);
        WpfScreen wpfScreen = new WpfScreen(screen);
        return wpfScreen;
    }

    public static WpfScreen GetScreenFrom(Point point)
    {
        int x = (int) Math.Round(point.X);
        int y = (int) Math.Round(point.Y);

        // are x,y device-independent-pixels ??
        System.Drawing.Point drawingPoint = new System.Drawing.Point(x, y);
        Screen screen = System.Windows.Forms.Screen.FromPoint(drawingPoint);
        WpfScreen wpfScreen = new WpfScreen(screen);

        return wpfScreen;
    }

    public static WpfScreen Primary
    {
        get { return new WpfScreen(System.Windows.Forms.Screen.PrimaryScreen); }
    }

    private readonly Screen screen;

    internal WpfScreen(System.Windows.Forms.Screen screen)
    {
        this.screen = screen;
    }

    public Rect DeviceBounds
    {
        get { return this.GetRect(this.screen.Bounds); }
    }

    public Rect WorkingArea
    {
        get { return this.GetRect(this.screen.WorkingArea); }
    }

    private Rect GetRect(Rectangle value)
    {
        // should x, y, width, height be device-independent-pixels ??
        return new Rect
                   {
                       X = value.X,
                       Y = value.Y,
                       Width = value.Width,
                       Height = value.Height
                   };
    }

    public bool IsPrimary
    {
        get { return this.screen.Primary; }
    }

    public string DeviceName
    {
        get { return this.screen.DeviceName; }
    }
}
Nils
fuente
Gracias por esta gran envoltura pequeña, tenga en cuenta que el global :: Rect necesitaba convertirse a simplemente Rect cuando lo usaba con WPF 3.5.
Andy Dent
1
Me gusta esto. Seguro que necesita un poco de trabajo, pero no espero encontrar soluciones al 100%.
jeff
4
Funciona genial. Acabo de extender el método GetRect para devolver el Rect en píxeles independientes del dispositivo: private Rect GetRect (valor del rectángulo) {var pixelWidthFactor = SystemParameters.WorkArea.Width / this.screen.WorkingArea.Width; var pixelHeightFactor = SystemParameters.WorkArea.Height / this.screen.WorkingArea.Height; return new Rect {X = value.X * pixelWidthFactor, Y = value.Y * pixelHeightFactor, Width = value.Width * pixelWidthFactor, Height = value.Height * pixelHeightFactor}; }
Jürgen Bayer
1
Creo que agregar el código de @ JürgenBayer mejorará aún más su respuesta. Tuve el problema con los píxeles independientes del dispositivo y el código de Jürgen lo resolvió. Gracias a los dos.
Bruno V
3
@ Jürgen: Creo que su método solo funciona en circunstancias muy específicas. Si "this.screen" tiene una relación de aspecto diferente a la del monitor principal (que su método siempre usa como referencia en lugar del monitor actual), obtendrá incorrectamente diferentes factores de escala para el ancho y la altura, lo que generará dimensiones de pantalla incorrectas. Si la pantalla actual tiene una configuración de DPI diferente a la pantalla principal, los límites serán incorrectos. En mi sistema, cada valor del Rect devuelto es (tremendamente) incorrecto.
wilford
27

Aquí amigo. Esto le dará solo el ancho y alto del área de trabajo.

System.Windows.SystemParameters.WorkArea.Width
System.Windows.SystemParameters.WorkArea.Height
Guilherme Ferreira
fuente
13
"Obtiene el tamaño del área de trabajo en el monitor principal". - no es lo que estaba buscando ....
Nils
10

Esto le dará la pantalla actual basada en la parte superior izquierda de la ventana, simplemente llame a this.CurrentScreen () para obtener información sobre la pantalla actual.

using System.Windows;
using System.Windows.Forms;

namespace Common.Helpers
{
    public static class WindowHelpers
     {
        public static Screen CurrentScreen(this Window window)
         {
             return Screen.FromPoint(new System.Drawing.Point((int)window.Left,(int)window.Top));
         }
     }
}
EJ
fuente
El usuario busca las dimensiones de la pantalla actual, en lugar de la pantalla principal.
greggannicott
3
esto devuelve la pantalla actual, basada en la posición superior izquierda de la ventana desde la que llama a la función auxiliar. Pero debo estar perdiendo algo en esta pregunta, según el puntaje de mi respuesta.
EJ
Quizás greggannicott quiso publicar su comentario en una de las otras respuestas, ya que es completamente irrelevante para esta.
Jim Balter
@ jim-balter Votado: en realidad, esta es la mejor respuesta aquí, necesitaba la pantalla para obtener el área de trabajo y luego asegurarme de que mi diálogo no exceda el límite, publicaré mi solución aquí. Felicitaciones a EJ por su rápida respuesta al punto.
Juv
^ comentario extraño.
Jim Balter
5

Tómese el tiempo para explorar los miembros de SystemParameters.

  • VirtualScreenWidth
  • VirtualScreenHeight

Estos incluso tienen en cuenta las posiciones relativas de las pantallas.

Solo probado con dos monitores.

dana
fuente
9
dana - No he probado esto, pero ¿VirtualScreen * no devuelve el tamaño completo de todas las pantallas? - Necesito específicamente el tamaño de una pantalla (aquella en la que reside la ventana actual).
Nils
1
VirtualScreen parece referirse al tamaño de todas las pantallas
Thomas
1
Una mía devolvió el tamaño de todas mis 4 pantallas combinadas.
DJ van Wyk
3

¿Por qué no usar esto?

var interopHelper = new WindowInteropHelper(System.Windows.Application.Current.MainWindow);
var activeScreen = Screen.FromHandle(interopHelper.Handle);
Matteo Zilio
fuente
La pantalla es Windows.Forms en lugar de WPF, pero este es un punto de partida. Si observa la solución que utilicé en ese entonces ( stackoverflow.com/a/2118993/180156 ), esto es exactamente lo que hice; sin embargo, lo terminé System.Windows.Forms.Screenpara hacer frente al píxel independiente del dispositivo
Nils
3

Si está familiarizado con el uso de la clase System.Windows.Forms , puede agregar una referencia de la clase System.Windows.Forms a su proyecto:

Explorador de soluciones -> Referencias -> Agregar referencias ... -> (Ensamblados: Marco) -> desplácese hacia abajo y verifique el ensamblaje System.Windows.Forms -> Aceptar .

Ahora puede agregar usando System.Windows.Forms; declaración y use la pantalla en su proyecto wpf como antes.

Phương Trần
fuente
Esta es, con mucho, la solución más sencilla. Me pregunto: además de agregar un conjunto bastante grande, ¿hay alguna buena razón para no hacerlo de esta manera?
AeonOfTime
3

También necesitaba la dimensión actual de la pantalla, específicamente el área de trabajo, que devolvió el rectángulo excluyendo el ancho de la barra de tareas.

Lo usé para reposicionar una ventana, que se abre hacia la derecha y hacia abajo hasta donde está posicionado el mouse. Dado que la ventana es bastante grande, en muchos casos salió de los límites de la pantalla. El siguiente código se basa en @ej respuesta: Esto le dará la pantalla actual ... . La diferencia es que también muestro mi algoritmo de reposicionamiento, que supongo que es en realidad el punto.

El código:

using System.Windows;
using System.Windows.Forms;

namespace MySample
{

    public class WindowPostion
    {
        /// <summary>
        /// This method adjust the window position to avoid from it going 
        /// out of screen bounds.
        /// </summary>
        /// <param name="topLeft">The requiered possition without its offset</param>
        /// <param name="maxSize">The max possible size of the window</param>
        /// <param name="offset">The offset of the topLeft postion</param>
        /// <param name="margin">The margin from the screen</param>
        /// <returns>The adjusted position of the window</returns>
        System.Drawing.Point Adjust(System.Drawing.Point topLeft, System.Drawing.Point maxSize, int offset, int margin)
        {
            Screen currentScreen = Screen.FromPoint(topLeft);
            System.Drawing.Rectangle rect = currentScreen.WorkingArea;

            // Set an offset from mouse position.
            topLeft.Offset(offset, offset);

            // Check if the window needs to go above the task bar, 
            // when the task bar shadows the HUD window.
            int totalHight = topLeft.Y + maxSize.Y + margin;

            if (totalHight > rect.Bottom)
            {
                topLeft.Y -= (totalHight - rect.Bottom);

                // If the screen dimensions exceed the hight of the window
                // set it just bellow the top bound.
                if (topLeft.Y < rect.Top)
                {
                    topLeft.Y = rect.Top + margin;
                }
            }

            int totalWidth = topLeft.X + maxSize.X + margin;
            // Check if the window needs to move to the left of the mouse, 
            // when the HUD exceeds the right window bounds.
            if (totalWidth > rect.Right)
            {
                // Since we already set an offset remove it and add the offset 
                // to the other side of the mouse (2x) in addition include the 
                // margin.
                topLeft.X -= (maxSize.X + (2 * offset + margin));

                // If the screen dimensions exceed the width of the window
                // don't exceed the left bound.
                if (topLeft.X < rect.Left)
                {
                    topLeft.X = rect.Left + margin;
                }
            }

            return topLeft;
        }
    }
}

Algunas explicaciones:

1) topLeft - position of the top left at the desktop (works                     
   for multi screens - with different aspect ratio).                            
            Screen1              Screen2                                        
        ─  ┌───────────────────┐┌───────────────────┐ Screen3                   
        ▲  │                   ││                   │┌─────────────────┐  ─     
        │  │                   ││                   ││   ▼-            │  ▲     
   1080 │  │                   ││                   ││                 │  │     
        │  │                   ││                   ││                 │  │ 900 
        ▼  │                   ││                   ││                 │  ▼     
        ─  └──────┬─────┬──────┘└──────┬─────┬──────┘└──────┬────┬─────┘  ─     
                 ─┴─────┴─            ─┴─────┴─            ─┴────┴─             
           │◄─────────────────►││◄─────────────────►││◄───────────────►│        
                   1920                 1920                1440                
   If the mouse is in Screen3 a possible value might be:                        
   topLeft.X=4140 topLeft.Y=195                                                 
2) offset - the offset from the top left, one value for both                    
   X and Y directions.                                                          
3) maxSize - the maximal size of the window - including its                     
   size when it is expanded - from the following example                        
   we need maxSize.X = 200, maxSize.Y = 150 - To avoid the expansion            
   being out of bound.                                                          

   Non expanded window:                                                         
   ┌──────────────────────────────┐ ─                                           
   │ Window Name               [X]│ ▲                                           
   ├──────────────────────────────┤ │                                           
   │         ┌─────────────────┐  │ │ 100                                       
   │  Text1: │                 │  │ │                                           
   │         └─────────────────┘  │ │                                           
   │                         [▼]  │ ▼                                           
   └──────────────────────────────┘ ─                                           
   │◄────────────────────────────►│                                             
                 200                                                            

   Expanded window:                                                             
   ┌──────────────────────────────┐ ─                                           
   │ Window Name               [X]│ ▲                                           
   ├──────────────────────────────┤ │                                           
   │         ┌─────────────────┐  │ │                                           
   │  Text1: │                 │  │ │                                           
   │         └─────────────────┘  │ │ 150                                       
   │                         [▲]  │ │                                           
   │         ┌─────────────────┐  │ │                                           
   │  Text2: │                 │  │ │                                           
   │         └─────────────────┘  │ ▼                                           
   └──────────────────────────────┘ ─                                           
   │◄────────────────────────────►│                                             
                 200                                                            
4) margin - The distance the window should be from the screen                   
   work-area - Example:                                                          
   ┌─────────────────────────────────────────────────────────────┐ ─            
   │                                                             │ ↕ Margin     
   │                                                             │ ─            
   │                                                             │              
   │                                                             │              
   │                                                             │              
   │                          ┌──────────────────────────────┐   │              
   │                          │ Window Name               [X]│   │              
   │                          ├──────────────────────────────┤   │              
   │                          │         ┌─────────────────┐  │   │              
   │                          │  Text1: │                 │  │   │              
   │                          │         └─────────────────┘  │   │              
   │                          │                         [▲]  │   │              
   │                          │         ┌─────────────────┐  │   │              
   │                          │  Text2: │                 │  │   │              
   │                          │         └─────────────────┘  │   │              
   │                          └──────────────────────────────┘   │ ─            
   │                                                             │ ↕ Margin     
   ├──────────────────────────────────────────────────┬──────────┤ ─            
   │[start] [♠][♦][♣][♥]                              │en│ 12:00 │              
   └──────────────────────────────────────────────────┴──────────┘              
   │◄─►│                                                     │◄─►│              
    Margin                                                    Margin            

* Note that this simple algorithm will always want to leave the cursor          
  out of the window, therefor the window will jumps to its left:                
  ┌─────────────────────────────────┐        ┌─────────────────────────────────┐
  │                  ▼-┌──────────────┐      │  ┌──────────────┐▼-             │
  │                    │ Window    [X]│      │  │ Window    [X]│               │
  │                    ├──────────────┤      │  ├──────────────┤               │
  │                    │       ┌───┐  │      │  │       ┌───┐  │               │
  │                    │  Val: │   │  │ ->   │  │  Val: │   │  │               │
  │                    │       └───┘  │      │  │       └───┘  │               │
  │                    └──────────────┘      │  └──────────────┘               │
  │                                 │        │                                 │
  ├──────────────────────┬──────────┤        ├──────────────────────┬──────────┤
  │[start] [][][]     │en│ 12:00 │        │[start] [][][]     │en│ 12:00 │
  └──────────────────────┴──────────┘        └──────────────────────┴──────────┘
  If this is not a requirement, you can add a parameter to just use             
  the margin:                                                                   
  ┌─────────────────────────────────┐        ┌─────────────────────────────────┐
  │                  ▼-┌──────────────┐      │                ┌─▼-───────────┐ │
  │                    │ Window    [X]│      │                │ Window    [X]│ │
  │                    ├──────────────┤      │                ├──────────────┤ │
  │                    │       ┌───┐  │      │                │       ┌───┐  │ │
  │                    │  Val: │   │  │ ->   │                │  Val: │   │  │ │
  │                    │       └───┘  │      │                │       └───┘  │ │
  │                    └──────────────┘      │                └──────────────┘ │
  │                                 │        │                                 │
  ├──────────────────────┬──────────┤        ├──────────────────────┬──────────┤
  │[start] [][][]     │en│ 12:00 │        │[start] [][][]     │en│ 12:00 │
  └──────────────────────┴──────────┘        └──────────────────────┴──────────┘
* Supports also the following scenarios:
  1) Screen over screen:
       ┌─────────────────┐  
       │                 │
       │                 │
       │                 │
       │                 │
       └─────────────────┘
     ┌───────────────────┐ 
     │                   │ 
     │  ▼-               │ 
     │                   │ 
     │                   │ 
     │                   │ 
     └──────┬─────┬──────┘ 
           ─┴─────┴─       
  2) Window bigger than screen hight or width
     ┌─────────────────────────────────┐        ┌─────────────────────────────────┐ 
     │                                 │        │ ┌──────────────┐                │
     │                                 │        │ │ Window    [X]│                │
     │                  ▼-┌────────────│─┐      │ ├──────────────┤ ▼-             │
     │                    │ Window    [│]│      │ │       ┌───┐  │                │
     │                    ├────────────│─┤ ->   │ │  Val: │   │  │                │ 
     │                    │       ┌───┐│ │      │ │       └───┘  │                │
     │                    │  Val: │   ││ │      │ │       ┌───┐  │                │
     │                    │       └───┘│ │      │ │  Val: │   │  │                │
     ├──────────────────────┬──────────┤ │      ├──────────────────────┬──────────┤
     │[start] [♠][♦][♣]     │en│ 12:00 │ │      │[start] [♠][♦][♣]     │en│ 12:00 │
     └──────────────────────┴──────────┘ │      └──────────────────────┴──────────┘
                          │       ┌───┐  │        │       └───┘  │
                          │  Val: │   │  │        └──────────────┘
                          │       └───┘  │
                          └──────────────┘


     ┌─────────────────────────────────┐             ┌─────────────────────────────────┐     
     │                                 │             │                                 │ 
     │                                 │             │ ┌───────────────────────────────│───┐
     │    ▼-┌──────────────────────────│────────┐    │ │ W▼-dow                        │[X]│
     │      │ Window                   │     [X]│    │ ├───────────────────────────────│───┤
     │      ├──────────────────────────│────────┤    │ │       ┌───┐      ┌───┐      ┌─┤─┐ │
     │      │       ┌───┐      ┌───┐   │  ┌───┐ │ -> │ │  Val: │   │ Val: │   │ Val: │ │ │ │
     │      │  Val: │   │ Val: │   │ Va│: │   │ │    │ │       └───┘      └───┘      └─┤─┘ │
     │      │       └───┘      └───┘   │  └───┘ │    │ └───────────────────────────────│───┘
     ├──────────────────────┬──────────┤────────┘    ├──────────────────────┬──────────┤
     │[start] [♠][♦][♣]     │en│ 12:00 │             │[start] [♠][♦][♣]     │en│ 12:00 │     
     └──────────────────────┴──────────┘             └──────────────────────┴──────────┘     
  • No tuve más remedio que usar el formato de código (de lo contrario, los espacios en blanco se habrían perdido).
  • Originalmente, esto apareció en el código anterior como un <remark><code>...</code></remark>
Juv
fuente
1

Entiendo las demandas. La cuestión es que existen métodos WPF para obtener esos valores, pero sí, uno de los contribuyentes tiene razón, no directamente. La solución no es obtener todas esas soluciones, sino cambiar el enfoque inicial de acuerdo con un diseño y desarrollo limpios.

A) Configure la ventana principal inicial en pantalla

B) Obtenga los valores para ActualWindow que incluyen una tonelada de métodos útiles de WPF

C) Puede agregar tantas ventanas como desee para el comportamiento que desea tener, como redimensionable, minimizado lo que sea ... pero ahora siempre puede acceder a la pantalla cargada y renderizada

Tenga cuidado con el siguiente ejemplo, hay un código que hace que sea necesario usar ese tipo de enfoque, sin embargo, debería funcionar (le daría los puntos para cada una de las esquinas de su pantalla): Ejemplo de trabajo en una sola, Monitor dual y diferentes resoluciones (dentro de la clase de ventana principal Primal):

InitializeComponent();
[…]
ActualWindow.AddHandler(Window.LoadedEvent, new RoutedEventHandler(StartUpScreenLoaded));

Evento enrutado:

private void StartUpScreenLoaded(object sender, RoutedEventArgs e)
    {
        Window StartUpScreen = sender as Window;

        // Dispatcher Format B:
        Dispatcher.Invoke(new Action(() =>
        {
            // Get Actual Window on Loaded
            StartUpScreen.InvalidateVisual();
            System.Windows.Point CoordinatesTopRight = StartUpScreen.TranslatePoint(new System.Windows.Point((StartUpScreen.ActualWidth), (0d)), ActualWindow);
            System.Windows.Point CoordinatesBottomRight = StartUpScreen.TranslatePoint(new System.Windows.Point((StartUpScreen.ActualWidth), (StartUpScreen.ActualHeight)), ActualWindow);
            System.Windows.Point CoordinatesBottomLeft = StartUpScreen.TranslatePoint(new System.Windows.Point((0d), (StartUpScreen.ActualHeight)), ActualWindow);

            // Set the Canvas Top Right, Bottom Right, Bottom Left Coordinates
            System.Windows.Application.Current.Resources["StartUpScreenPointTopRight"] = CoordinatesTopRight;
            System.Windows.Application.Current.Resources["StartUpScreenPointBottomRight"] = CoordinatesBottomRight;
            System.Windows.Application.Current.Resources["StartUpScreenPointBottomLeft"] = CoordinatesBottomLeft;
        }), DispatcherPriority.Loaded);
    }
Dororo
fuente
1

Si usa cualquier ventana de pantalla completa (que la tenga WindowState = WindowState.Maximized, WindowStyle = WindowStyle.None), puede ajustar su contenido System.Windows.Controls.Canvasasí:

<Canvas Name="MyCanvas" Width="auto" Height="auto">
...
</Canvas>

Luego puede usar MyCanvas.ActualWidthy MyCanvas.ActualHeightpara obtener la resolución de la pantalla actual, teniendo en cuenta la configuración de DPI y en unidades independientes del dispositivo. No agrega márgenes como lo hace la ventana maximizada.

(Canvas acepta mensajes de correo UIElementelectrónico como elementos secundarios, por lo que debería poder usarlo con cualquier contenido).

zvizesna
fuente
0

Center Window en la pantalla en XAML y WindowStartupLocation="CenterOwner"luego llamar en WindowLoaded ()

double ScreenHeight = 2 * (Top + 0.5 * Height);

mikesl
fuente
-4
double screenWidth = System.Windows.SystemParameters.PrimaryScreenWidth;
double screenhight= System.Windows.SystemParameters.PrimaryScreenHeight;
Rahul chalkhure
fuente
4
Al igual que la respuesta anterior, esto es solo para la pantalla principal . Necesitaba la pantalla actual .
Nils
-4

Funciona con

this.Width = System.Windows.SystemParameters.VirtualScreenWidth;
this.Height = System.Windows.SystemParameters.VirtualScreenHeight;

Probado en 2 monitores.

Hoang
fuente
Si miras la respuesta del 18 de mayo de 2010 a las 15:52, que era exactamente la misma que la tuya, verás que VirtualScreenabarca todas las pantallas, ¡así que esto nunca funcionará si tienes más de una pantalla!
Nils