Jak uzyskać rozmiar bieżącego ekranu w WPF?

87

Wiem, że mogę uzyskać rozmiar głównego ekranu, używając

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

Ale jak uzyskać rozmiar bieżącego ekranu? (Użytkownicy korzystający z wielu ekranów nie zawsze używają ekranu głównego i nie wszystkie ekrany używają tej samej rozdzielczości, prawda?)

Byłoby miło móc uzyskać dostęp do rozmiaru z XAML, ale wystarczyłoby to z kodu (C #).

Nils
źródło
1
Zdefiniuj „bieżący”. Okno może znajdować się jednocześnie na więcej niż jednym ekranie.
Jim Balter

Odpowiedzi:

13

O ile wiem, nie ma natywnej funkcji WPF do uzyskania wymiarów bieżącego monitora. Zamiast tego można użyć funkcji PInvoke z natywnymi funkcjami wielu monitorów wyświetlania , opakować je w klasę zarządzaną i uwidocznić wszystkie właściwości, które są potrzebne do wykorzystania ich z XAML.

Anvaka
źródło
Właśnie tego się obawiałem - potrzeby P / Invoke the stuff lub uzyskania dostępu do System.Windows.Forms.Screen. A kiedy to robię, zawsze muszę obliczyć "piksele niezależne od urządzenia" ... Ale dzięki.
Nils
Tak ... Może funkcja SystemParameters.ConvertPixel () również Ci pomoże. To wewnętrzne, ale Reflectorowi to nie
przeszkadza :)
74

Stworzyłem małe opakowanie wokół ekranu z System.Windows.Forms, obecnie wszystko działa ... Nie jestem pewien co do "pikseli niezależnych od urządzenia".

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
źródło
Dzięki za to świetne małe opakowanie, zauważ, że global :: Rect wymagało konwersji do zwykłego Rect, gdy użyłem z WPF 3.5.
Andy Dent,
1
Lubię to. Oczywiście wymaga to trochę pracy, ale nie spodziewam się znaleźć 100% rozwiązań.
Jeff
4
Działa świetnie. Właśnie rozszerzyłem metodę GetRect, aby zwracała Rect w niezależnych od urządzenia pikselach: private Rect GetRect (wartość Rectangle) {var pixelWidthFactor = SystemParameters.WorkArea.Width / this.screen.WorkingArea.Width; var pixelHeightFactor = SystemParameters.WorkArea.Height / this.screen.WorkingArea.Height; zwraca nowy Rect {X = value.X * pixelWidthFactor, Y = value.Y * pixelHeightFactor, Width = value.Width * pixelWidthFactor, Height = value.Height * pixelHeightFactor}; }
Jürgen Bayer
1
Wierzę, że dodanie kodu z @ JürgenBayer jeszcze bardziej poprawi twoją odpowiedź. Miałem problem z pikselami niezależnymi od urządzenia i kod Jürgena go rozwiązał. Dziękuję wam obu.
Bruno V
3
@ Jürgen: Uważam, że twoja metoda działa tylko w bardzo szczególnych okolicznościach. Jeśli „this.screen” ma inny współczynnik proporcji niż monitor podstawowy (którego metoda zawsze używa jako odniesienia zamiast bieżącego monitora), nieprawidłowo uzyskasz różne współczynniki skali dla szerokości i wysokości, co prowadzi do nieprawidłowych wymiarów ekranu. Jeśli bieżący ekran ma inne ustawienie DPI niż ekran główny, granice będą nieprawidłowe. W moim systemie każda wartość zwróconego Recta jest (dziko) niepoprawna.
wilford
27

Tutaj, kolego. To da ci tylko szerokość i wysokość obszaru roboczego

System.Windows.SystemParameters.WorkArea.Width
System.Windows.SystemParameters.WorkArea.Height
Guilherme Ferreira
źródło
13
„Pobiera rozmiar obszaru roboczego na głównym monitorze”. - nie to, czego szukałem…
Nils
10

To da ci aktualny ekran oparty na lewym górnym rogu okna, po prostu wywołaj this.CurrentScreen (), aby uzyskać informacje o bieżącym ekranie.

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
źródło
Użytkownik szuka wymiarów bieżącego ekranu, a nie ekranu głównego.
greggannicott,
3
zwraca to bieżący ekran, na podstawie lewej górnej pozycji okna, z którego wywołujesz funkcję pomocniczą. Ale chyba czegoś brakuje mi w tym pytaniu, biorąc pod uwagę wynik mojej odpowiedzi.
EJ,
Być może greggannicott chciał zamieścić swój komentarz do jednej z pozostałych odpowiedzi, ponieważ jest to zupełnie nieistotne dla tej odpowiedzi.
Jim Balter
@ jim-balter Głosowano - Właściwie to jest najlepsza odpowiedź tutaj, potrzebowałem ekranu, aby uzyskać obszar roboczy, a następnie upewnić się, że moje okno dialogowe nie przekracza limitu, opublikuję tutaj swoje rozwiązanie. Uznanie dla EJ za szybką odpowiedź.
Juv
^ dziwny komentarz.
Jim Balter
5

Poświęć trochę czasu na przejrzenie elementów członkowskich SystemParameters.

  • VirtualScreenWidth
  • VirtualScreenHeight

Uwzględniają one nawet względne położenie ekranów.

Testowany tylko z dwoma monitorami.

dana
źródło
9
dana - nie testowałem tego, ale czy VirtualScreen * nie zwraca pełnego rozmiaru wszystkich ekranów? - Szczególnie potrzebuję rozmiaru jednego ekranu (tego, na którym znajduje się bieżące okno).
Nils
1
Wydaje się, że VirtualScreen odnosi się do rozmiaru wszystkich ekranów
Thomas
1
Jeden mój zwrócił rozmiar wszystkich 4 moich ekranów razem.
DJ van Wyk,
3

Dlaczego po prostu tego nie użyć?

var interopHelper = new WindowInteropHelper(System.Windows.Application.Current.MainWindow);
var activeScreen = Screen.FromHandle(interopHelper.Handle);
Matteo Zilio
źródło
Ekran to Windows.Forms, a nie WPF - ale to jest punkt wyjścia. Jeśli spojrzysz na rozwiązanie, którego użyłem wtedy ( stackoverflow.com/a/2118993/180156 ), to jest dokładnie to, co zrobiłem - jednak zapakowałem, System.Windows.Forms.Screenaby poradzić sobie z niezależnym od urządzenia pikselem
Nils
3

Jeśli znasz klasę System.Windows.Forms , możesz po prostu dodać odwołanie do klasy System.Windows.Forms do swojego projektu:

Eksplorator rozwiązań -> Referencje -> Dodaj odwołania ... -> (Assemblies: Framework) -> przewiń w dół i sprawdź zestaw System.Windows.Forms -> OK .

Teraz możesz dodać za pomocą System.Windows.Forms; oświadczenie i użyj screen w swoim projekcie wpf tak jak wcześniej.

Phương Trần
źródło
To zdecydowanie najłatwiejsze rozwiązanie. Zastanawiam się - czy oprócz dodania dość dużego zespołu są jakieś dobre powody, aby tego nie robić w ten sposób?
AeonOfTime,
3

Potrzebowałem również aktualnego wymiaru ekranu, w szczególności obszaru roboczego, który zwrócił prostokąt z wyłączeniem szerokości paska zadań.

Użyłem go do zmiany położenia okna, które jest otwierane w prawo i w dół do miejsca, w którym znajduje się mysz. Ponieważ okno jest dość duże, w wielu przypadkach wychodziło poza granice ekranu. Poniższy kod jest oparty na @ej odpowiedź: To daje bieżący ekran ... . Różnica polega na tym, że pokazuję również mój algorytm repozycjonowania, o który zakładam, że tak naprawdę jest.

Kod:

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

Kilka wyjaśnień:

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 │     
     └──────────────────────┴──────────┘             └──────────────────────┴──────────┘     
  • Nie miałem innego wyboru, jak tylko użyć formatu kodu (w przeciwnym razie białe spacje zostałyby utracone).
  • Pierwotnie pojawił się w powyższym kodzie jako plik <remark><code>...</code></remark>
Juv
źródło
1

Rozumiem wymagania. Chodzi o to, że istnieją metody WPF do pobierania tych wartości - ale tak, jeden z współautorów ma rację, nie bezpośrednio. Rozwiązaniem nie jest uzyskanie wszystkich tych obejść, ale zmiana początkowego podejścia zgodnie z czystym projektem i rozwojem.

A) Ustaw początkowe okno główne na ekran

B) Uzyskaj wartości dla ActualWindow, w tym mnóstwo przydatnych metod WPF

C) Możesz dodać tyle okien, ile chcesz, aby uzyskać zachowanie, które chcesz, na przykład zmienić rozmiar, zminimalizować cokolwiek… ale teraz zawsze możesz uzyskać dostęp do załadowanego i renderowanego ekranu

Proszę uważać na poniższy przykład, istnieje kod, który sprawia, że ​​konieczne jest użycie tego rodzaju podejścia, jednak powinno działać (dałoby ci punkty za każdy z rogów twojego ekranu): Przykład roboczy na pojedynczym, Podwójny monitor i różne rozdzielczości (w klasie pierwotnego okna głównego):

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

Wydarzenie kierowane:

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
źródło
1

Jeśli używasz dowolnego okna pełnoekranowego (posiadającego WindowState = WindowState.Maximized, WindowStyle = WindowStyle.None), możesz zawinąć jego zawartość w System.Windows.Controls.Canvasnastępujący sposób:

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

Następnie możesz użyć MyCanvas.ActualWidthiMyCanvas.ActualHeight aby uzyskać rozdzielczość bieżącego ekranu, z uwzględnieniem ustawień DPI oraz w jednostkach niezależnych od urządzenia. Nie dodaje żadnych marginesów, tak jak robi to samo zmaksymalizowane okno.

(Canvas akceptuje UIElements jako dzieci, więc powinieneś być w stanie używać go z dowolną zawartością).

zvizesna
źródło
0

Wyśrodkuj okno na ekranie w XAML, WindowStartupLocation="CenterOwner"a następnie wywołaj WindowLoaded ()

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

mikesl
źródło
-4
double screenWidth = System.Windows.SystemParameters.PrimaryScreenWidth;
double screenhight= System.Windows.SystemParameters.PrimaryScreenHeight;
Rahul Chalkhure
źródło
4
Podobnie jak w poprzedniej odpowiedzi, dotyczy to tylko ekranu głównego . Potrzebowałem aktualnego ekranu.
Nils
-4

Działa z plikami

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

Testowany na 2 monitorach.

Hoang
źródło
jeśli spojrzysz na odpowiedź z 18 maja 2010 o 15:52 - która była dokładnie taka sama jak twoja, zobaczysz, że VirtualScreenobejmuje wszystkie ekrany - więc to nigdy nie zadziała, jeśli masz więcej niż jeden ekran!
Nils