Предоставленное решение подходило для .Net Framework 4.5, однако, с масштабированием Windows 10 DPI и Framework 4.6.x, добавляющими различные степени его поддержки, конструктор, используемый для измерения текста, теперь помечен [Obsolete]
вместе с любымконструкторы этого метода, которые не включают параметр pixelsPerDip
.
К сожалению, он немного сложнее, но с новыми возможностями масштабирования это приведет к большей точности.
PixelsPerDip
Согласно MSDN, это представляет:
Значение Pixels Per Density Independent Pixel, которое является эквивалентом масштабного коэффициента.Например, если DPI экрана составляет 120 (или 1,25, потому что 120/96 = 1,25), рисуется 1,25 пикселя на пиксель, независимый от плотности.DIP - это единица измерения, используемая WPF для независимости от разрешения устройства и точек на дюйм.
Вот моя реализация выбранного ответа, основанная на указаниях Microsoft / WPF-Samples GitHub репозиторий с поддержкой масштабирования DPI.
Для полной поддержки 1020 * поддержки масштабирования DPI с Windows 10 Anniversary (ниже кода) требуется дополнительная конфигурация, которую я не смог заставить работать,но без него это работает на одном мониторе с настроенным масштабированием (и учитывает изменения масштабирования).Документ Word в приведенном выше репозитории является источником этой информации, поскольку мое приложение не запустится, как только я добавлю эти значения. Этот пример кода из того же репо также послужил хорошей отправной точкой.
public partial class MainWindow : Window
{
private DpiScale m_dpiInfo;
private readonly object m_sync = new object();
public MainWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private Size MeasureString(string candidate)
{
DpiInfo dpiInfo;
lock (m_dpiInfo)
dpiInfo = m_dpiInfo;
if (dpiInfo == null)
throw new InvalidOperationException("Window must be loaded before calling MeasureString");
var formattedText = new FormattedText(candidate, CultureInfo.CurrentUICulture,
FlowDirection.LeftToRight,
new Typeface(this.textBlock.FontFamily,
this.textBlock.FontStyle,
this.textBlock.FontWeight,
this.textBlock.FontStretch),
this.textBlock.FontSize,
Brushes.Black,
dpiInfo.PixelsPerDip);
return new Size(formattedText.Width, formattedText.Height);
}
// ... The Rest of Your Class ...
/*
* Event Handlers to get initial DPI information and to set new DPI information
* when the window moves to a new display or DPI settings get changed
*/
private void OnLoaded(object sender, RoutedEventArgs e)
{
lock (m_sync)
m_dpiInfo = VisualTreeHelper.GetDpi(this);
}
protected override void OnDpiChanged(DpiScale oldDpiScaleInfo, DpiScale newDpiScaleInfo)
{
lock (m_sync)
m_dpiInfo = newDpiScaleInfo;
// Probably also a good place to re-draw things that need to scale
}
}
Другие требования
Согласно документации на Microsoft / WPF-Samples, вынеобходимо добавить некоторые параметры в манифест приложения, чтобы охватить возможность Windows 10 Anniversary иметь разные настройки DPI для каждого дисплея в конфигурациях с несколькими мониторами.Можно предположить, что без этих настроек событие OnDpiChanged может не возникать, когда окно перемещается с одного экрана на другой с другими настройками, что делает ваши измерения по-прежнему основанными на предыдущем DpiScale
.Приложение, которое я писал, было для меня, одного, и у меня нет такой установки, поэтому мне было нечего тестировать, и когда я следовал инструкциям, я получил приложение, которое не запускалось из-за манифеста.ошибок, поэтому я сдался, но было бы неплохо посмотреть на это и настроить манифест вашего приложения, чтобы он содержал:
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitor</dpiAwareness>
</windowsSettings>
</application>
Согласно документации:
Комбинация [этих] двух тегов имеет следующий эффект: 1) Per-Monitor для> = Windows 10 Anniversary Update 2) Система