Как узнать разрешение экрана wpf

Обновлено: 07.07.2024

Я занимаюсь макетированием на панели управления, и вам нужно скрыть тексты кнопок, когда не хватает места. Я успешно сделал это в Windows Forms уже, и теперь я портировал эту логику в WPF. Но здесь есть огромная проблема: для того, чтобы мой алгоритм работал правильно, мне нужно знать желаемую ширину элемента управления контейнером (чтобы узнать, какой размер потребуется, если бы все было видно) и фактическую ширину элемента управления (чтобы знать, как это действительно так, и достаточно места для желаемой ширины). Первый доступен, хотя иногда и немного назад. (Если есть больше свободного места, чем требуется, DeseredSize увеличивается, чтобы заполнить все, хотя меньше будет хорошо.) Последний полностью недоступен!

Я пробовал с ActualWidth, но если сетка шире окна, ActualWidth больше, чем на самом деле. Так что это уже должно быть неправильно. Затем я попробовал RenderSize, но это то же самое. Использование Arrange после моего вызова Measure приводит к более странности.

Мне нужно знать, насколько широк контроль на самом деле, а не насколько он верит в себя. Как определить размер?

Обновление: Хорошо, вот какой-то код. Это уже довольно долго для этого вопроса и еще неполно. Это из оконного кода.

спросил(а) 2020-03-03T16:34:03+03:00 1 год, 8 месяцев назад

Из того, что я понял, вы используете Grid, но вы устанавливаете ширину столбцов в Auto, а как насчет использования * для ширины вашей сетки. Column istead of Auto. Если "Авто" затем "Сетка" растягивает свою ширину и высоту, чтобы соответствовать ее содержимому, поэтому ваша Grid.Width больше ширины окон. Когда вы используете *, столбец не заботится о содержимом, но он всегда будет находиться внутри границ окон.

Теперь, после реализации *, вы используете column.width/height, который находится внутри границ окна в качестве вашей конечной ширины/высоты, и внутри Grid вы можете измерить размер вашего встроенного элемента управления. То, как вы получаете конечный размер и размер управляемых элементов.

Покажите еще код /​​xaml, и мы сможем вам помочь.

Отредактировано:

Как насчет этого? Мой псевдокод поможет вам в дальнейшем?

ответил(а) 2020-03-03T16:51:50.971511+03:00 1 год, 8 месяцев назад

Оказалось, что WPF не даст мне прогнозируемых размеров Grid, который содержит все столбцы с авторазделом с элементами кнопок в них. Но родительский элемент этой Grid, независимо от того, что это и как он оформлен, предоставляет полезную информацию об этом. Таким образом, мое решение состоит в том, чтобы вставить еще один уровень контейнера Grid между тем, что было уже там, и моей реальной сеткой макета панели инструментов и сравнить разные размеры обоих. Центральный тест, чтобы выяснить, будет ли сетка соответствовать в данном пространстве, теперь такова:

Он выполняет итерацию по всем приоритетным классам элементов, которые могут быть свернуты вместе (независимо от того, расположены ли они на сетке) и сбрасывают все элементы в классе (группе). Затем макет внутренней сетки обновляется, чтобы отражать изменения кнопок, а внутренняя сетка RenderSize сравнивается с внешней сеткой ActualWidth. Если он меньше, он вписывается, и больше предметов не нужно рушиться.

Все это вызывается из события LayoutUpdated внутренней сетки, все еще предотвращая рекурсию через переменную блокировки. Это позволяет мне реагировать на изменения размера любой кнопки на панели инструментов, например, когда текст был обновлен.

Поскольку событие LayoutCompleted, похоже, запускается асинхронно, переменная блокировки должна оставаться установленной до следующего завершения макета, и не может быть снова сброшена в конце обработчика LayoutUpdated:

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

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

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

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

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

  • VirtualScreenWidth
  • VirtualScreenHeight

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

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

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

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

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

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

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

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

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

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

Microsoft Logo

Gray Pipe

Приносим извинения. Запрошенное содержимое было удалено. Вы будете автоматически перенаправлены через 1 секунду.

Спрашивающий

Общие обсуждения

Казалось бы все просто:

double h = SystemParameters.PrimaryScreenHeight;

double w = SystemParameters.PrimaryScreenWidth;

SystemParameters.PrimaryScreenHeight, SystemParameters.PrimaryScreenWidth и установленное в настройках разрешение экрана. Как точно узнать этот коэффициент (1.0 или 1.25).

Все ответы

Установленное в настройках разрешение экрана равно

SystemParameters .PrimaryScreenWidth/SystemParameters.CaretWidth по ширине и SystemParameters .PrimaryScreenHeight/SystemParameters.CaretWidth по высоте.


Предыдущее вроде выкидывает таскбар.

SystemParameters .PrimaryScreenWidth = 1536

SystemParameters .PrimaryScreenHeight = 864;

Point p = MyWindow.myImage. PointToScreen(pt).

Может следует делать так:

Point pt = new Point ();

Point p = MyWindow.myimage.PointToScreen(pt);

Point pf = app.acyWindow.PointFromScreen(p);

myImage 2. Left = pf.X;

Point p = MyWindow . myimage . PointToScreen ( pt );

myImage2.Left = p.X * SystemParameters .CaretWidth;

[ return : MarshalAs ( UnmanagedType .Bool)]

public static extern Boolean EnumDisplaySettings([ param : MarshalAs ( UnmanagedType .LPTStr)] string lpszDeviceName, [ param : MarshalAs ( UnmanagedType .U4)] int iModeNum,

[ In , Out ] ref DEVMODE lpDevMode);

DEVMODE mode = new DEVMODE ();

mode.dmSize = ( ushort ) Marshal .SizeOf(mode);

EnumDisplaySettings( null , ENUM_CURRENT_SETTINGS, ref mode);

double widthPoint = SystemParameters .PrimaryScreenWidth / (double)mode.dmPelsWidth

double heighthPoint = SystemParameters .PrimaryScreenHeight/ (double)mode.dmPelsHeight;

Традиционные Windows-приложения связаны определенными предположениями относительно разрешения экрана. Обычно разработчики рассчитывают на стандартное разрешение монитора (вроде 1024x768 пикселей) и проектируют свои окна с учетом этого, стараясь обеспечить разумное поведение при изменении размеров в большую и меньшую сторону.

Проблема в том, что пользовательский интерфейс в традиционных Windows-приложениях не является масштабируемым. В результате, если вы используете монитор с высоким разрешением, который располагает пиксели более плотно, окно приложения становится меньше и читать текст в нем труднее. Эта проблема особенно актуальна для новых мониторов, которые имеют высокую плотность пикселей и соответственно работают с более высоким разрешением.

Например, легче встретить мониторы (особенно на портативных компьютерах), которые имеют плотность пикселей в 120 dpi или 144 dpi (точек на дюйм), чем более традиционные 96 dpi. При их встроенном разрешении эти мониторы располагают пиксели более плотно, создавая напрягающие глаз мелкие элементы управления и текст. В идеале приложения должны использовать более высокую плотность пикселей, чтобы отобразить больше деталей. Например, монитор с высоким разрешением может отображать одинакового размера значки панели инструментов, но использовать дополнительные пиксели для отображения мелкой графики. Подобным образом можно сохранить некоторую базовую компоновку, но обеспечить более высокую четкость деталей.

По разным причинам такое решение было невозможно в прошлом. Хотя можно изменять размер графического содержимого, нарисованного в GDI/GDI+, компонент User32 (который генерирует визуальное представление распространенных элементов управления) не поддерживает реального масштабирования.

WPF не страдает от этой проблемы, потому что самостоятельно визуализирует все элементы пользовательского интерфейса — от простых фигур до таких распространенных элементов управления, как кнопки. В результате если вы создаете кнопку шириной в 1 дюйм на обычном мониторе, она останется шириной в 1 дюйм и на мониторе с высоким разрешением. WPF просто визуализирует ее более детализировано, с большим количеством пикселей.

Так выглядит картина в целом, но нужно уточнить еще несколько деталей. Самое важное, что следует осознать — WPF базирует свое масштабирование на системной установке DPI, а не на DPI физического дисплейного устройства. Это совершенно логично — в конце концов, если вы отображаете приложение на 100-дюймовом проекторе, то, скорее всего, отойдете подальше на несколько шагов и будете ожидать увидеть огромную версию окон. Конечно, не желательно, чтобы WPF масштабировал приложение, уменьшая его до "нормального" размера. Аналогично, если вы используете портативный компьютер с дисплеем высокого разрешения, то хотите увидеть несколько уменьшенные окна; это цена, которую приходится платить за то, чтобы уместить всю информацию на маленьком экране. Более того, у разных пользователей разные предпочтения на этот счет. Некоторым нужны расширенные подробности, в то время как другие хотят увидеть больше содержимого.

Так каким же образом WPF определяет, насколько большим должно быть окно приложения? Краткий ответ состоит в том, что при вычислении размеров WPF использует системную установку DPI. Но чтобы понять, как это в действительности работает, необходимо более детально ознакомиться с системой измерений WPF.

Единицы WPF

Окно WPF и все элементы внутри него измеряются в независимых от устройства единицах. Такая единица определена как 1 /96 дюйма. Чтобы понять, что это означает на практике, нужно рассмотреть пример.

Предположим, что вы создаете в WPF маленькую кнопку размером 96x96 единиц. Если вы используете стандартную установку Windows DPI (96 dpi), то каждая независимая от устройства единица измерения соответствует одному реальному физическому пикселю. Это потому, что WPF использует следующее вычисление:

По сути, WPF предполагает, что ему нужно 96 пикселей, чтобы отобразить один дюйм, потому что Windows сообщает ему об этом через системную настройку DPI. Однако в действительности это зависит от применяемого дисплейного устройства. Например, рассмотрим 20-дюймовый жидкокристаллический монитор с максимальным разрешением в 1600x1200 пикселей. Используя теорему Пифагора, вы можете вычислить плотность пикселей для этого монитора, как показано ниже:

В этом случае плотность пикселей составляет 100 dpi — немного больше того, что предполагает Windows. В результате на этом мониторе кнопка размером 96x96 пикселей будет несколько меньше одного дюйма.

С другой стороны, рассмотрим 15-дюймовый жидкокристаллический монитор с разрешением 1024x768 пикселей. Здесь плотность пикселей составит около 85 dpi, поэтому кнопка размером 96x96 пикселей окажется размером немного больше 1 дюйма.

В обоих случаях, если вы уменьшите размер экрана (скажем, переключившись на разрешение 800x600), то кнопка (и любой другой экранный элемент) станет пропорционально больше. Причина в том, что системная установка DPI останется 96 dpi. Другими словами, Windows продолжает предполагать, что 96 пикселей составляют дюйм, несмотря на то, что при меньшем разрешении потребуется существенно меньше пикселей.

Возможно, вам известно, что жидкокристаллические мониторы создаются с единственным разрешением, которое называется естественным разрешением. При более низком разрешении монитору приходится использовать интерполяцию, чтобы заполнить лишние пиксели, это может вызвать нерезкость. Чтобы получить наилучшее качество изображения, всегда лучше использовать естественное разрешение. Если хотите иметь более крупные окна, кнопки и текст, рассмотрите вместо этого возможность модификации системной установки DPI.

Системная установка DPI

До сих пор пример кнопки WPF работал точно так же, как любой другой интерфейсный элемент в Windows-приложении любого иного типа. Отличие проявляется при изменении вашей системной установки DPI. В предыдущем поколении Windows это средство иногда называли крупными шрифтами. Это потому, что системная установка DPI влияет на размер системных шрифтов, часто оставляя прочие детали неизменными.

Многие Windows-приложения не полностью поддерживают увеличенные установки DPI. В худшем случае увеличение системной установки DPI может привести к появлению окон, в которых некоторое содержимое увеличено, а другое — нет, что может привести к утере части содержимого или даже к нефункциональным окнам.

Здесь поведение WPF отличается. WPF воспринимает системную установку DPI естественным образом и без особых затрат. Например, если вы измените системную установку DPI на 120 dpi (распространенный выбор пользователей экранов с большим разрешением), WPF предполагает, что для заполнения дюйма пространства нужно 120 пикселей. WPF использует следующее вычисление для определения того, как он должен транслировать логические единицы в физические пиксели устройства:

Другими словами, когда вы устанавливаете системную настройку DPI в 120 dpi, то механизм визуализации WPF предполагает, что одна независимая от устройства единица измерения соответствует 1,25 пикселя. Если вы отображаете кнопку 96x96, то физический ее размер составит 120x120 пикселей (потому что 96 х 1,25 = 120). Именно такого результата вы и ожидаете — кнопка размером в 1 дюйм имеет такой же размер на мониторе с повышенной плотностью пикселей.

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

В зависимости от системной установки DPI вычисляемый размер пикселя может быть выражен дробным значением. Можно предположить, что WPF просто округляет все размеры до ближайшего пикселя. Однако по умолчанию WPF поступает несколько иначе. Если грань элементов приходится на точку между пикселями, WPF использует сглаживание, чтобы размыть эту грань. Это может показаться странным решением, но на самом деле оно вполне оправдано. Элементы управления не обязательно должны иметь прямые четкие грани, если для их отображения применяется специально отрисованная графика, поэтому некоторая степень сглаживания все равно необходима.

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

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

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

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

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

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

  • У меня не было выбора, кроме как использовать формат кода (в противном случае пробелы были бы потеряны).
  • Первоначально это появилось в приведенном выше коде как <remark><code>. </code></remark>

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

  • VirtualScreenWidth
  • VirtualScreenHeight

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

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

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

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

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

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

Я сделал это, сначала переместив окно на монитор, размер которого я хотел получить. Затем, получив hwnd MainWindow приложения (не обязательно в главном окне, но мое приложение имеет только одно окно) и IntPtr на монитор. Затем я создал новый экземпляр структуры MONITORINFOEX и вызвал метод GetMonitorInfo.

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

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

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

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

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

Читайте также: