Como posso obter as dimensões da tela ativa?

142

O que estou procurando é o equivalente a System.Windows.SystemParameters.WorkArea ao monitor em que a janela está atualmente.

Esclarecimento: A janela em questão é WPF, não WinForm.

chilltemp
fonte
2
Alteração da resposta aceita para refletir a melhor maneira de fazer isso no WPF. System.Windows.SystemParameters. *
chilltemp
1
A obsessão por não usar um espaço para nome WinForms parece estranha para mim, não ganha nada; em vez disso, deixa você sem as ferramentas necessárias para resolver adequadamente o problema.
Jeff Yates
4
Para mim, não se trata de WinForms vs. WPF. É sobre aprender algo novo. Não consigo decidir qual caminho é melhor se não aprender dos dois lados.
Chilltemp # 3/10
3
Bem, nesse cenário, não há "nos dois sentidos", pois há apenas uma maneira de fazer isso, que é usar o material WinForms.
Jeff Yates
@ Jeff Yates: Você está correto. Desenterrei o projeto original para o qual fiz essa pergunta e descobri que usava as propriedades PrimaryScreen *. Eles resolveram minhas necessidades do dia, mas não a pergunta real que eu fiz. Desculpe pelo desvio; Alterei a resposta aceita de acordo.
Chilltemp

Respostas:

143

Screen.FromControl, Screen.FromPointE Screen.FromRectangledeve ajudá-lo com isso. Por exemplo, no WinForms, seria:

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

Não conheço uma chamada equivalente para WPF. Portanto, você precisa fazer algo como este método de extensão.

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
fonte
1
Talvez minha marcação não tenha deixado claro que estou usando janelas WPF, não WinForms. Eu não tenho o System.Windows.Forms.dll mencionado e não funcionaria de qualquer maneira, pois o WPF tem sua própria árvore de herança.
Chilltemp 31/10/08
1
De nada. Peço desculpas por não ter chegado diretamente à resposta - tive que investigar o que estava disponível no WPF antes de atualizar minha postagem.
Jeff Yates
Isso funciona para colocar uma janela na borda direita: var bounds = this.GetScreen (). WorkingArea; this.Left = bounds.Right - this.Width; Mas requer referências a System.Windows.Forms e System.Drawing, o que não é o ideal.
Anthony
1
@evios Cuidado que esta chamada não reconhece DPI; você precisará fazer cálculos.
precisa
6
No meu aplicativo VS 2015 WPF direcionado ao .NET 4.5 no meu sistema de 4 monitores no Windows 10 Pro (v10.0.14393) com windowno monitor acima do meu primário (por exemplo, seu Top < 0), FromHandleretornei o Screendo meu monitor primário (mesmo que windowestivesse completamente dentro o monitor secundário)!?! Suspiro. Parece que vou ter que procurar no Screen.AllScreensArray sozinho. Por que as coisas não podem "simplesmente funcionar"?!? Arrrrgh.
Tom
62

Você pode usar isso para obter os limites do espaço de trabalho da área de trabalho da tela principal:

System.Windows.SystemParameters.WorkArea

Isso também é útil para obter apenas o tamanho da tela principal:

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

Pyttroll
fonte
19
Estou confuso ... Isso parece retornar apenas as dimensões da tela principal. Eu quero saber as dimensões da tela da janela está atualmente em ...
VitalyB
1
isso não responde à pergunta e, mesmo que você queira apenas obter o tamanho da exibição principal, os SystemParameters (no WPF) estão incorretos. eles retornam unidades independentes de dispositivo e não pixels. para uma melhor implementação ver esta resposta: stackoverflow.com/questions/254197/...
Patrick Klug
1
PrimaryScreenHeight / Width funcionou exatamente como o esperado e o MSDN possui o seguinte: "Obtém um valor que indica a altura da tela, em pixels, do monitor principal". A WorkArea não diz especificamente pixels, mas a documentação e os exemplos de uso me levam a acreditar que também está em pixels. Você tem um link para algo que indica o uso de unidades independentes de dispositivo?
Chilltemp # 3/10
17

Adicionando uma solução que não usa WinForms, mas NativeMethods. Primeiro, você precisa definir os métodos nativos necessários.

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

E, em seguida, obtenha a alça do monitor e as informações do monitor assim.

        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
fonte
1
Você consegue o tamanho real da tela se houver fator de escala de suas janelas (100% / 125% / 150% / 200%)?
Kiquenet 23/07/19
12

Adicionar ao ffpf

Screen.FromControl(this).Bounds
defeituoso
fonte
12

Cuidado com o fator de escala de suas janelas (100% / 125% / 150% / 200%). Você pode obter o tamanho real da tela usando o seguinte código:

SystemParameters.FullPrimaryScreenHeight
SystemParameters.FullPrimaryScreenWidth
aDoubleSo
fonte
1
Isso é para a tela principal - e se a janela do aplicativo estiver em uma tela virtual (estendida) (por exemplo, se você tiver um ou dois monitores externos conectados ao seu PC)?
Matt
4

Eu queria ter a resolução da tela antes de abrir a primeira das minhas janelas, então aqui está uma solução rápida para abrir uma janela invisível antes de realmente medir as dimensões da tela (você precisa adaptar os parâmetros da janela à sua janela para garantir que ambos estejam abertos em a mesma tela - principalmente a WindowStartupLocationé 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
fonte
3

Esta é uma " solução Center Screen DotNet 4.5 ", usando SystemParameters em vez de System.Windows.Forms ou My.Compuer.Screen : Como o Windows 8 alterou o cálculo da dimensão da tela, a única maneira de funcionar para mim é assim (cálculo da barra de tarefas incluído):

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

Tela central WPF XAML

Nasenbaer
fonte
instalação do instalador no WPF?
Kiquenet 23/07/19
A principal questão é sobre a posição da tela. Como o instalador Msi, Innosetup ou outros, criei meu próprio instalador com verificação de CPU, verificação de permissão, verificação de driver e muito mais, muito simples de usar. Essa é a captura de tela sobre.
Nasenbaer
3

Eu precisava definir o tamanho máximo do meu aplicativo de janela. Este pode ser alterado de acordo com a aplicação apresentada na tela principal ou na secundária. Para superar esse problema, criamos um método simples que mostrarei a seguir:

/// <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
fonte
1

no winforms C #, tenho o ponto de partida (por exemplo, quando temos vários monitor / diplay e um formulário está chamando outro) com a ajuda do seguinte 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
fonte
1

WinForms

Para configurações de vários monitores, você também precisará ter em conta a posição X e Y:

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

Este código de depuração deve executar bem o truque:

Você pode explorar as propriedades da classe Screen

Coloque todas as exibições em uma matriz ou lista usando Screen.AllScreens e capture o índice da exibição atual e suas propriedades.

insira a descrição da imagem aqui

C # (convertido de VB por Telerik - verifique novamente)

        {
    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 telas

Daniel Santos
fonte