Как получить размер текущего экрана в WPF?

87

Я знаю, что могу получить размер основного экрана, используя

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

Но как мне узнать размер текущего экрана? (Пользователи многоэкранного режима не всегда используют основной экран, и не все экраны имеют одинаковое разрешение, верно?)

Было бы неплохо получить доступ к размеру из XAML, но этого будет достаточно из кода (C #).

Нильс
источник
1
Определите «текущий». Окно может находиться более чем на одном экране одновременно.
Джим Балтер

Ответы:

13

Насколько мне известно, встроенной функции WPF для получения размеров текущего монитора нет. Вместо этого вы можете PInvoke встроить функции нескольких мониторов , обернуть их в управляемый класс и предоставить все свойства, необходимые для их использования из XAML.

Анвака
источник
Это именно то, чего я боялся - необходимости P / Invoke или доступа к System.Windows.Forms.Screen каким-то образом. И при этом мне всегда нужно вычислять "независимые от устройства пиксели" ... Тем не менее, спасибо.
Nils
Да ... Возможно, вам поможет функция SystemParameters.ConvertPixel (). Это внутреннее, но Рефлектору все равно
:)
74

Я создал небольшую оболочку вокруг экрана из System.Windows.Forms, в настоящее время все работает ... Не уверен, что насчет "аппаратно-независимых пикселей".

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; }
    }
}
Нильс
источник
Спасибо за эту замечательную маленькую оболочку, обратите внимание, что global :: Rect нужно было преобразовать в простой Rect, когда я использовал с WPF 3.5.
Энди Дент
1
Мне это нравится. Конечно, нужно немного поработать, но я не ожидаю найти 100% решений.
Джефф
4
Работает отлично. Я просто расширил метод GetRect, чтобы возвращать Rect в независимых от устройства пикселях: private Rect GetRect (значение Rectangle) {var pixelWidthFactor = SystemParameters.WorkArea.Width / this.screen.WorkingArea.Width; var pixelHeightFactor = SystemParameters.WorkArea.Height / this.screen.WorkingArea.Height; вернуть новый Rect {X = значение.X * pixelWidthFactor, Y = value.Y * pixelHeightFactor, Width = value.Width * pixelWidthFactor, Height = value.Height * pixelHeightFactor}; }
Jürgen Bayer
1
Я считаю, что добавление кода из @ JürgenBayer еще больше улучшит ваш ответ. У меня была проблема с пикселями, независимыми от устройства, и код от Юргена решил ее. Спасибо вам обоим.
Bruno V
3
@ Jürgen: Я считаю, что ваш метод работает только при очень определенных обстоятельствах. Если «this.screen» имеет другое соотношение сторон, чем основной монитор (который ваш метод всегда использует в качестве эталона вместо текущего монитора), вы получите неверные коэффициенты масштабирования для ширины и высоты, что приведет к неправильным размерам экрана. Если текущий экран имеет другую настройку DPI, чем основной экран, все границы будут неправильными. В моей системе каждое значение возвращенного Rect (безумно) неверно.
Wilford
27

Вот приятель. Это даст вам только ширину и высоту рабочей области.

System.Windows.SystemParameters.WorkArea.Width
System.Windows.SystemParameters.WorkArea.Height
Гильерме Феррейра
источник
13
«Получает размер рабочей области на основном мониторе». - не то, что я искал ....
Нильс
10

Это даст вам текущий экран, основанный на левом верхнем углу окна, просто вызовите this.CurrentScreen (), чтобы получить информацию о текущем экране.

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
источник
Пользователь ищет размеры текущего экрана, а не основного экрана.
greggannicott 05
3
это возвращает текущий экран, основанный на верхнем левом положении окна, из которого вы вызываете вспомогательную функцию. Но я должен что-то упустить в этом вопросе, исходя из оценки моего ответа.
EJ
Возможно, Грегганникотт хотел опубликовать свой комментарий к одному из других ответов, поскольку он совершенно не имеет отношения к этому.
Джим Балтер
@ jim-balter проголосовал за - На самом деле это лучший ответ здесь, мне нужен экран, чтобы получить рабочую область, а затем убедиться, что мой диалог не выходит за пределы, я опубликую свое решение здесь. Престижность EJ за быстрый и по существу ответ.
Джув
^ странный комментарий.
Джим Балтер
5

Найдите время, чтобы просмотреть элементы SystemParameters.

  • VirtualScreenWidth
  • VirtualScreenHeight

Они даже учитывают взаимное расположение экранов.

Проверено только с двумя мониторами.

дана
источник
9
дана - я не тестировал это, но разве VirtualScreen * не возвращает полный размер всех экранов? - Мне специально нужен размер одного экрана (того, на котором находится текущее окно).
Нильс
1
VirtualScreen, кажется, относится к размеру всех экранов
Томас
1
Одна мина вернула размер всех 4 моих экранов вместе взятых.
DJ van Wyk
3

Почему бы просто не использовать это?

var interopHelper = new WindowInteropHelper(System.Windows.Application.Current.MainWindow);
var activeScreen = Screen.FromHandle(interopHelper.Handle);
Маттео Зилио
источник
Экран - это Windows.Forms, а не WPF, но это отправная точка. Если вы посмотрите на решение, которое я использовал тогда ( stackoverflow.com/a/2118993/180156 ), это именно то, что я сделал - однако я обернул, System.Windows.Forms.Screenчтобы справиться с независимым от устройства пикселем
Нильс
3

Если вы знакомы с использованием класса System.Windows.Forms, вы можете просто добавить ссылку на класс System.Windows.Forms в свой проект:

Обозреватель решений -> Ссылки -> Добавить ссылки ... -> (Сборки: Framework) -> прокрутите вниз и проверьте сборку System.Windows.Forms -> ОК .

Теперь вы можете добавить using System.Windows.Forms; оператор и используйте screen в своем проекте wpf, как и раньше.

Phng Trần
источник
Это, безусловно, самое простое решение. Интересно - кроме добавления довольно большой сборки, есть ли веские причины не делать этого таким образом?
AeonOfTime
3

Мне также понадобился текущий размер экрана, в частности, рабочая область, которая вернула прямоугольник, исключая ширину панели задач.

Я использовал его для изменения положения окна, которое открывается вправо и вниз, туда, где расположена мышь. Поскольку окно довольно большое, во многих случаях оно выходило за пределы экрана. Следующий код основан на @ej ответ: Это даст вам текущий экран ... . Разница в том, что я также показываю свой алгоритм изменения положения, в котором, как я полагаю, и есть суть.

Код:

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

Некоторые пояснения:

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 │     
     └──────────────────────┴──────────┘             └──────────────────────┴──────────┘     
  • У меня не было выбора, кроме как использовать формат кода (иначе были бы потеряны пробелы).
  • Первоначально это появилось в приведенном выше коде как <remark><code>...</code></remark>
Джув
источник
1

Я понимаю требования. Дело в том, что существуют методы WPF для получения этих значений, но да, один из участников прав, а не напрямую. Решение состоит не в том, чтобы найти все эти обходные пути, а в изменении первоначального подхода в соответствии с чистым дизайном и разработкой.

A) Установите начальное главное окно на экран

Б) Получите значения для ActualWindow, включая массу полезных методов WPF

C) Вы можете добавить столько окон, сколько захотите, для желаемого поведения, например, изменение размера, сворачивание чего угодно ... но теперь вы всегда можете получить доступ к загруженному и визуализированному экрану

Будьте осторожны со следующим примером, есть некоторый код, который заставляет использовать такой подход, однако он должен работать (он даст вам баллы для каждого из углов экрана): Рабочий пример для одиночного, Двойной монитор и разные разрешения (в классе основного главного окна):

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

Маршрутизированное событие:

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);
    }
Дороро
источник
1

Если вы используете любое полноэкранное окно (имеющее его WindowState = WindowState.Maximized, WindowStyle = WindowStyle.None), вы можете обернуть его содержимое System.Windows.Controls.Canvasследующим образом:

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

Затем вы можете использовать MyCanvas.ActualWidthи, MyCanvas.ActualHeightчтобы получить разрешение текущего экрана с учетом настроек DPI и в единицах измерения, независимых от устройства. Он не добавляет полей, как это делает само развернутое окно.

(Canvas принимает UIElements как дочерние элементы, поэтому вы сможете использовать его с любым контентом.)

Звезена
источник
0

WindowStartupLocation="CenterOwner"Отцентрируйте окно на экране в XAML, затем вызовите WindowLoaded ()

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

Mikesl
источник
-4
double screenWidth = System.Windows.SystemParameters.PrimaryScreenWidth;
double screenhight= System.Windows.SystemParameters.PrimaryScreenHeight;
Рахул чалкхуре
источник
4
Как и предыдущий ответ, это только для основного экрана. Мне нужен был текущий экран.
Нильс
-4

Работает с

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

Проверено на 2-х мониторах.

Hoang
источник
если вы посмотрите на ответ от 18 мая 2010 года в 15:52 - который был точно таким же, как ваш, вы увидите, что он VirtualScreenохватывает все экраны - так что это никогда не сработает, если у вас более одного экрана!
Nils