我目前正在处理我们的 WPF 应用程序中的一些高 DPI 问题(.NET 4.6.1 - 系统 DPI 感知处于活动状态)。
通常,该应用程序会按照我们的预期进行 - 根据当前显示的 DPI 设置进行缩放,当将其从屏幕 A @ 100% 移动到屏幕 B @ 150% 时,它会正确地“在半点”更改其整体比例。
大多数未解决的问题是因为我们有一些基于像素/DIP 的计算没有考虑 DPI 设置。我通过计算正确的 DPI 值来解决这个问题:
var source = PresentationSource.FromVisual(this);
var dpiX = source?.CompositionTarget?.TransformToDevice.M11 ?? 1;
var dpiY = source?.CompositionTarget?.TransformToDevice.M22 ?? 1;
在那里我发现了第一件奇怪的事情(至少对我来说):
- 如果主显示器设置为例如 125%,我得到
dpiX
所有屏幕的 1.25,即使是 100% 的辅助屏幕,但所有像素值已经乘以 1.25(意味着 1600x1200 像素屏幕的工作尺寸为 2000x1500) . - 如果主屏幕处于 100% 并且辅助屏幕处于例如 150% 则正好相反:我总是得到 1
dpiX
,但所有值都已经正确并且不需要更正(=> 或乘法/潜水1 不会破坏它)。
但现在我的实际问题是:
我将一些弹出窗口放置在其放置目标的中心,并具有以下绑定:
<Popup.HorizontalOffset>
<MultiBinding Converter="{lth:CenterConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="PlacementTarget.ActualWidth" />
<Binding RelativeSource="{RelativeSource Self}" Path="Child.ActualWidth" />
<Binding RelativeSource="{RelativeSource Self}" Path="." />
</MultiBinding>
</Popup.HorizontalOffset>
和转换器:
public class CenterConverter : MarkupExtension, IMultiValueConverter
{
public override object ProvideValue(IServiceProvider serviceProvider) => this;
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Any(v => v == DependencyProperty.UnsetValue))
return Double.NaN;
double placementTargetWidth = (double)values[0];
double elementWidth = (double)values[1];
var offset = (placementTargetWidth - elementWidth) / 2;
////if (values.Length >= 3 && values[2] is Visual)
////{
//// var source = PresentationSource.FromVisual((Visual)values[2]);
//// var dpiX = source?.CompositionTarget?.TransformToDevice.M11 ?? 1;
//// offset *= -1; //dpiX;
////}
return offset;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotSupportedException(); }
}
对于案例 2,如果没有注释掉的代码,一切都已经正常工作,但对于案例 1,我尝试将 DPI 值相乘,但最终正确的做法是将其乘以使其-1
正常工作。
为什么会这样?
我怎样才能有效地检测到什么时候需要呢?dpiX > 1
?
我也对缩放问题或整个中心放置的其他解决方案持开放态度。
PS:我正在运行安装了 .NET 4.7 的 Windows 10 1703(由于某些其他原因,应用程序仍以 4.6.1 为目标)。
更新:
我创建了一个演示解决方案:https
://github.com/chrfin/HorizontalOffsetError
如果主屏幕处于 100% 是正确的:
但如果主屏幕是 125% 则关闭:
但如果我添加*-1 到偏移量再次正确:
...但为什么?