Comment puis-je obtenir les dimensions de l'écran actif?

142

Ce que je recherche est l'équivalent du System.Windows.SystemParameters.WorkAreamoniteur sur lequel se trouve actuellement la fenêtre.

Clarification: la fenêtre en question ne l'est WPFpas WinForm.

chilltemp
la source
2
Réponse acceptée modifiée pour refléter la meilleure façon de le faire à partir de WPF. System.Windows.SystemParameters. *
chilltemp
1
L'obsession de ne pas utiliser d'espace de noms WinForms me semble étrange, cela ne vous rapporte rien; au lieu de cela, il vous laisse sans les outils dont vous avez besoin pour résoudre correctement le problème.
Jeff Yates
4
Pour moi, il ne s'agit pas de WinForms contre WPF. Il s'agit d'apprendre quelque chose de nouveau. Je ne peux pas décider quelle est la meilleure manière si je n'apprends pas les deux.
chilltemp
3
Eh bien, dans ce scénario, il n'y a pas "dans les deux sens" car il n'y a qu'une seule façon de faire cela, qui est d'utiliser les trucs WinForms.
Jeff Yates
@Jeff Yates: Vous avez raison. J'ai déterré le projet original pour lequel j'avais posé cette question et j'ai découvert que j'avais utilisé les propriétés PrimaryScreen *. Ils ont résolu mes besoins du jour, mais pas la question que j'ai posée. Désolé pour le run-around; J'ai changé la réponse acceptée en conséquence.
chilltemp

Réponses:

143

Screen.FromControl, Screen.FromPointet Screen.FromRectangledevrait vous aider. Par exemple dans WinForms, ce serait:

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

Je ne connais pas d'appel équivalent pour WPF. Par conséquent, vous devez faire quelque chose comme cette méthode d'extension.

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
la source
1
Peut-être que mon balisage n'indiquait pas clairement que j'utilisais des fenêtres WPF, pas WinForms. Je n'ai pas le System.Windows.Forms.dll référencé, et cela ne fonctionnerait pas de toute façon car WPF a son propre arbre d'héritage.
chilltemp
1
De rien. Je m'excuse de ne pas aller directement à la réponse - j'ai dû enquêter sur ce qui était disponible dans WPF avant de mettre à jour mon message.
Jeff Yates
Cela fonctionne pour mettre une fenêtre sur le bord droit: var bounds = this.GetScreen (). WorkingArea; this.Left = bounds.Right - this.Width; Mais il nécessite des références à System.Windows.Forms et System.Drawing, ce qui n'est pas idéal.
Anthony
1
@devios Attention, cet appel n'est pas compatible DPI; vous devrez faire des calculs.
Lynn Crumbling
6
Dans mon application VS 2015 WPF ciblant .NET 4.5 sur mon système à 4 moniteurs sur Windows 10 Pro (v10.0.14393) avec windowsur le moniteur au - dessus de mon principal (par exemple, son Top < 0), a FromHandlerenvoyé le Screenpour mon moniteur principal (même s'il windowétait complètement à l' intérieur le moniteur secondaire)!?! Soupir. Il semble que je devrais rechercher Screen.AllScreensmoi-même le tableau. Pourquoi les choses ne peuvent-elles pas "simplement fonctionner"?!? Arrrrgh.
Tom
62

Vous pouvez l'utiliser pour obtenir les limites de l'espace de travail du bureau de l'écran principal:

System.Windows.SystemParameters.WorkArea

Ceci est également utile pour obtenir uniquement la taille de l'écran principal:

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

Pyttroll
la source
19
Je suis confus ... Cela ne semble renvoyer que les dimensions principales de l'écran. Je veux connaître les dimensions de l'écran où se trouve actuellement la fenêtre ...
VitalyB
1
cela ne répond pas à la question et même si vous souhaitez simplement obtenir la taille de l'affichage principal, les SystemParameters (dans WPF) sont incorrects. ils renvoient des unités indépendantes de l'appareil et non des pixels. pour une meilleure implémentation, voir cette réponse: stackoverflow.com/questions/254197/…
Patrick Klug
1
PrimaryScreenHeight / Width a fonctionné exactement comme prévu et MSDN a les éléments suivants sur eux: «Obtient une valeur qui indique la hauteur de l'écran, en pixels, du moniteur d'affichage principal. WorkArea ne dit pas spécifiquement les pixels, mais la documentation et les exemples d'utilisation me portent à croire que c'est aussi en pixels. Avez-vous un lien vers quelque chose indiquant l'utilisation d'unités indépendantes de l'appareil?
chilltemp
17

Ajout d'une solution qui n'utilise pas WinForms mais NativeMethods à la place. Vous devez d'abord définir les méthodes natives nécessaires.

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

Et puis obtenez la poignée du moniteur et les informations du moniteur comme ça.

        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
la source
1
Pouvez-vous obtenir la taille réelle de l'écran s'il y a un facteur d'échelle de vos fenêtres (100% / 125% / 150% / 200%)?
Kiquenet
12

Ajouter à ffpf

Screen.FromControl(this).Bounds
défectueux
la source
12

Attention au facteur d'échelle de vos fenêtres (100% / 125% / 150% / 200%). Vous pouvez obtenir la taille réelle de l'écran en utilisant le code suivant:

SystemParameters.FullPrimaryScreenHeight
SystemParameters.FullPrimaryScreenWidth
aDoubleSo
la source
1
C'est pour l'écran principal - que se passe-t-il si la fenêtre de votre application est sur un écran virtuel (étendu) (c'est-à-dire que vous avez un ou deux moniteurs externes connectés à votre PC)?
Matt
4

Je voulais avoir la résolution de l'écran avant d'ouvrir la première de mes fenêtres, alors voici une solution rapide pour ouvrir une fenêtre invisible avant de mesurer réellement les dimensions de l'écran (vous devez adapter les paramètres de la fenêtre à votre fenêtre afin de vous assurer que les deux s'ouvrent le même écran - principalement le WindowStartupLocationest important)

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();
André
la source
3

Il s'agit d'une solution "Center Screen DotNet 4.5 ", utilisant SystemParameters au lieu de System.Windows.Forms ou My.Compuer.Screen : Depuis que Windows 8 a modifié le calcul de la dimension de l'écran, la seule façon dont cela fonctionne pour moi ressemble à ça (calcul de la barre des tâches inclus):

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

Écran central WPF XAML

Nasenbaer
la source
configuration du programme d'installation dans WPF?
Kiquenet
La question principale concerne la position de l'écran. Comme l'installateur Msi, Innosetup ou autres, j'ai créé mon propre installateur avec vérification du processeur, vérification des autorisations, vérification des pilotes et bien plus encore, très simple à utiliser. C'est la capture d'écran à propos.
Nasenbaer
3

J'avais besoin de définir la taille maximale de mon application de fenêtre. Celui-ci pourrait être modifié en fonction de l'affichage de l'application dans l'écran principal ou dans le secondaire. Pour surmonter ce problème, nous avons créé une méthode simple que je vous montre ensuite:

/// <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
la source
1

dans C # winforms, j'ai un point de départ (pour le cas où nous avons plusieurs moniteurs / affichages et un formulaire en appelle un autre) à l'aide de la méthode suivante:

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
la source
1

WinForms

Pour les configurations multi-moniteurs, vous aurez également besoin d'un compte pour la position X et Y:

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

Ce code de débogage devrait bien faire l'affaire:

Vous pouvez explorer les propriétés de la classe d'écran

Mettez tous les affichages dans un tableau ou une liste à l'aide de Screen.AllScreens puis capturez l'index de l'affichage actuel et ses propriétés.

entrez la description de l'image ici

C # (converti de VB par Telerik - Veuillez vérifier)

        {
    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 (code d'origine)

 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)

Liste des écrans

Daniel Santos
la source