Como obter o tamanho da tela atual no WPF?

87

Eu sei que posso obter o tamanho da tela principal usando

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

Mas como obtenho o tamanho da tela atual? (Os usuários de várias telas nem sempre usam a tela principal e nem todas as telas usam a mesma resolução, certo?)

Seria bom poder acessar o tamanho do XAML, mas fazer isso a partir do código (C #) seria suficiente.

Nils
fonte
1
Defina "atual". Uma janela pode estar em mais de uma tela ao mesmo tempo.
Jim Balter

Respostas:

13

Pelo que eu sei, não existe uma função WPF nativa para obter as dimensões do monitor atual. Em vez disso, você poderia PInvoke funções de monitores de exibição múltiplos nativos , envolvê-los em classe gerenciada e expor todas as propriedades necessárias para consumi-los do XAML.

Anvaka
fonte
Isso é exatamente o que eu temia - a necessidade de P / Invoke as coisas ou acessar System.Windows.Forms.Screen de alguma forma. E ao fazer isso, sempre preciso calcular os "pixels independentes do dispositivo" ... Obrigado, no entanto.
Nils
Sim ... Talvez a função SystemParameters.ConvertPixel () também ajude você. É interno, mas o Reflector não se importa
:)
74

Eu criei um pequeno wrapper em torno da Tela de System.Windows.Forms, atualmente tudo funciona ... Não tenho certeza sobre os "pixels independentes de dispositivo", porém.

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
fonte
Obrigado por este pequeno invólucro excelente, observe que o global :: Rect precisou ser convertido para Rect puro quando usei com WPF 3.5.
Andy Dent
1
Eu gosto disso. Claro que precisa de um pouco de trabalho, mas não espero encontrar soluções 100%.
jeff
4
Funciona bem. Acabei de estender o método GetRect para retornar o Rect em pixels independentes de dispositivo: private Rect GetRect (valor do retângulo) {var pixelWidthFactor = SystemParameters.WorkArea.Width / this.screen.WorkingArea.Width; var pixelHeightFactor = SystemParameters.WorkArea.Height / this.screen.WorkingArea.Height; retornar novo Rect {X = value.X * pixelWidthFactor, Y = value.Y * pixelHeightFactor, Width = value.Width * pixelWidthFactor, Height = value.Height * pixelHeightFactor}; }
Jürgen Bayer
1
Acredito que adicionar o código de @ JürgenBayer melhorará ainda mais sua resposta. Tive o problema com os pixels independentes do dispositivo e o código de Jürgen resolveu. Obrigado a ambos.
Bruno V
3
@ Jürgen: Acredito que seu método só funcione em circunstâncias muito específicas. Se "this.screen" tiver uma proporção de aspecto diferente do monitor principal (que seu método sempre usa como referência em vez do monitor atual), você obterá incorretamente fatores de escala diferentes para largura e altura levando a dimensões de tela incorretas. Se a tela atual tiver uma configuração de DPI diferente da tela principal, os limites estarão todos errados. No meu sistema, cada valor do Rect retornado está (descontroladamente) incorreto.
wilford
27

Aqui amigo. Isso fornecerá apenas a largura e a altura da área de trabalho

System.Windows.SystemParameters.WorkArea.Width
System.Windows.SystemParameters.WorkArea.Height
Guilherme Ferreira
fonte
13
"Obtém o tamanho da área de trabalho no monitor principal." - não é o que eu estava procurando ...
Nils
10

Isso lhe dará a tela atual com base no canto superior esquerdo da janela, basta chamar this.CurrentScreen () para obter informações sobre a tela atual.

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
fonte
O usuário está procurando as dimensões da tela atual, em vez da tela principal.
Greggannicott
3
isso retorna a tela atual, com base na posição superior esquerda da janela a partir da qual você chama a função auxiliar. Mas devo estar faltando alguma coisa a esta pergunta, com base na pontuação de minha resposta.
EJ
Talvez Greggannicott quisesse postar seu comentário em uma das outras respostas, já que é completamente irrelevante para esta.
Jim Balter
@ jim-balter Votado - Na verdade esta é a melhor resposta aqui, eu precisava da Tela para obter a área de trabalho e depois ter certeza que meu diálogo não está ultrapassando o limite, postarei minha solução aqui. Parabéns a EJ pela resposta rápida ao ponto.
Juv
^ comentário bizarro.
Jim Balter
5

Reserve um tempo para examinar os membros SystemParameters.

  • VirtualScreenWidth
  • VirtualScreenHeight

Estes levam em consideração até as posições relativas das telas.

Testado apenas com dois monitores.

dana
fonte
9
dana - Não testei, mas o VirtualScreen * não retorna o tamanho total de todas as telas? - Preciso especificamente do tamanho de uma tela (aquela em que reside a janela atual).
Nils
1
VirtualScreen parece referir-se ao tamanho de todas as telas
Thomas,
1
Uma mina retornou o tamanho de todas as 4 minhas telas combinadas.
DJ van Wyk de
3

Por que não apenas usar isso?

var interopHelper = new WindowInteropHelper(System.Windows.Application.Current.MainWindow);
var activeScreen = Screen.FromHandle(interopHelper.Handle);
Matteo Zilio
fonte
A tela é Windows.Forms em vez de WPF - mas este é um ponto de partida. Se você olhar para a solução que usei naquela época ( stackoverflow.com/a/2118993/180156 ), foi exatamente isso o que fiz - no entanto, resolvi System.Windows.Forms.Screenlidar com o pixel independente de dispositivo
Nils
3

Se você está familiarizado com o uso da classe System.Windows.Forms , pode simplesmente adicionar uma referência da classe System.Windows.Forms ao seu projeto:

Gerenciador de Soluções -> Referências -> Adicionar Referências ... -> (Assemblies: Framework) -> role para baixo e verifique System.Windows.Forms assembly -> OK .

Agora você pode adicionar usando System.Windows.Forms; declaração e use a tela em seu projeto wpf como antes.

Phương Trần
fonte
Esta é de longe a solução mais fácil. Eu me pergunto - além de adicionar uma montagem bastante grande, há algum bom motivo para não fazer dessa forma?
AeonOfTime
3

Eu também precisava da dimensão da tela atual, especificamente a área de trabalho, que retornou o retângulo excluindo a largura da barra de tarefas.

Usei-o para reposicionar uma janela, que é aberta à direita e para baixo onde o mouse está posicionado. Como a janela é bastante grande, em muitos casos ela saiu dos limites da tela. O código a seguir é baseado na resposta @ej: Isso fornecerá a tela atual ... . A diferença é que também mostro meu algoritmo de reposicionamento, que presumo que seja realmente o ponto.

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

Algumas explicações:

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 │     
     └──────────────────────┴──────────┘             └──────────────────────┴──────────┘     
  • Não tive escolha a não ser usar o formato de código (caso contrário, os espaços em branco teriam sido perdidos).
  • Originalmente, isso aparecia no código acima como um <remark><code>...</code></remark>
Juv
fonte
1

Eu entendo as demandas. O fato é que existem métodos WPF para obter esses valores - mas sim, um dos colaboradores está certo, não diretamente. A solução não é obter todas essas soluções alternativas, mas mudar a abordagem inicial de acordo com um design e desenvolvimento limpos.

A) Defina a janela principal inicial para tela

B) Obtenha os valores para a janela atual, incluindo uma tonelada de métodos WPF úteis

C) Você pode adicionar quantas janelas quiser para o comportamento que deseja, como redimensionável, minimizado o que for ... mas agora você sempre pode acessar a Tela Carregada e Renderizada

Tenha cuidado com o exemplo a seguir, existe algum Código que torna necessário o uso desse tipo de abordagem, no entanto, deve funcionar (daria a você os pontos para cada um dos cantos de sua tela): Exemplo de trabalho em single, Monitor duplo e diferentes resoluções (dentro da classe da janela principal primária):

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

Evento encaminhado:

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

Se você usar qualquer janela de tela inteira (com a sua WindowState = WindowState.Maximized, WindowStyle = WindowStyle.None), poderá agrupar seu conteúdo System.Windows.Controls.Canvasdesta forma:

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

Então você pode usar MyCanvas.ActualWidtheMyCanvas.ActualHeight para obter a resolução da tela atual, com as configurações de DPI levadas em consideração e em unidades independentes de dispositivo. Ele não adiciona nenhuma margem como a própria janela maximizada faz.

(O Canvas aceita UIElements como filhos, então você deve ser capaz de usá-lo com qualquer conteúdo.)

Zvizesna
fonte
0

Centralize a janela na tela em XAML WindowStartupLocation="CenterOwner"e chame WindowLoaded ()

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

mikesl
fonte
-4
double screenWidth = System.Windows.SystemParameters.PrimaryScreenWidth;
double screenhight= System.Windows.SystemParameters.PrimaryScreenHeight;
Rahul Chalkhure
fonte
4
Como a resposta anterior, isso é apenas para a Tela principal . Eu precisava da tela atual .
Nils
-4

Funciona com

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

Testado em 2 monitores.

Hoang
fonte
se você olhar para a resposta de 18 de maio de 2010 às 15:52 - que foi exatamente a mesma que a sua, você verá que VirtualScreenabrange todas as telas - então isso nunca funcionará se você tiver mais de uma tela!
Nils,