有没有一种方法可以禁用所有 WPF 应用程序的缩放,即使 windows 每个监视器或系统范围的缩放都有一定程度?
Is there a way to disable scaling for all the WPF application even if windows has some scale per monitor or system-wide scale?
我需要 WPF windows,它始终 1:1 具有物理像素(DPI 始终为 96),而此时我发现无法执行此操作:应用程序清单或 API 感知方法是无用的,它们只是改变了内容缩放的方式:作为位图或由应用程序缩放。我需要应用程序始终具有固定的 100% 比例,即使每个监视器或整个系统的系统设置为 200%。你们知道一些可以提供帮助的方法吗?
据我所知,您可以通过在应用程序清单中声明 True/PM
来抑制所有自动缩放,这意味着应用程序对缩放负全部责任,然后忽略 WM_DPICHANGED
消息什么时候来。
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
</windowsSettings>
</application>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
var source = PresentationSource.FromVisual(this) as HwndSource;
source?.AddHook(WndProc);
}
private const int WM_DPICHANGED = 0x02E0;
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_DPICHANGED)
{
handled = true;
}
return IntPtr.Zero;
}
}
我不太确定用户是否可以通过任何 OS 设置覆盖此行为。
对于那些正在寻找类似解决方案的人:
我发现无法强制应用程序不与操作系统一起缩放,但找到了如何保持 1:1 缩放。
您需要做的第一件事是定义应用程序是 dpi 感知的,因此它不会由系统缩放,而是由应用程序本身缩放。这是 app.manifest 代码:
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
</windowsSettings>
</application>
</assembly>
然后您将能够获得视觉对象的当前比例:
double xScale = PresentationSource.FromVisual(someVisual).CompositionTarget.TransformToDevice.M11;
double yScale = PresentationSource.FromVisual(someVisual).CompositionTarget.TransformToDevice.M22;
然后你可以将布局变换绑定到控件(在我的例子中是图像)以取消缩放效果:
<Image.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=_this, Path=ScaleX}"
ScaleY="{Binding ElementName=_this, Path=ScaleY}" />
</Image.LayoutTransform>
请注意比例应该倒置,因此 ScaleX 和 ScaleY 将具有这些值:
ScaleX = 1 / scaleX;
ScaleY = 1 / scaleY;
我需要 WPF windows,它始终 1:1 具有物理像素(DPI 始终为 96),而此时我发现无法执行此操作:应用程序清单或 API 感知方法是无用的,它们只是改变了内容缩放的方式:作为位图或由应用程序缩放。我需要应用程序始终具有固定的 100% 比例,即使每个监视器或整个系统的系统设置为 200%。你们知道一些可以提供帮助的方法吗?
据我所知,您可以通过在应用程序清单中声明 True/PM
来抑制所有自动缩放,这意味着应用程序对缩放负全部责任,然后忽略 WM_DPICHANGED
消息什么时候来。
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
</windowsSettings>
</application>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
var source = PresentationSource.FromVisual(this) as HwndSource;
source?.AddHook(WndProc);
}
private const int WM_DPICHANGED = 0x02E0;
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_DPICHANGED)
{
handled = true;
}
return IntPtr.Zero;
}
}
我不太确定用户是否可以通过任何 OS 设置覆盖此行为。
对于那些正在寻找类似解决方案的人:
我发现无法强制应用程序不与操作系统一起缩放,但找到了如何保持 1:1 缩放。
您需要做的第一件事是定义应用程序是 dpi 感知的,因此它不会由系统缩放,而是由应用程序本身缩放。这是 app.manifest 代码:
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
</windowsSettings>
</application>
</assembly>
然后您将能够获得视觉对象的当前比例:
double xScale = PresentationSource.FromVisual(someVisual).CompositionTarget.TransformToDevice.M11;
double yScale = PresentationSource.FromVisual(someVisual).CompositionTarget.TransformToDevice.M22;
然后你可以将布局变换绑定到控件(在我的例子中是图像)以取消缩放效果:
<Image.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=_this, Path=ScaleX}"
ScaleY="{Binding ElementName=_this, Path=ScaleY}" />
</Image.LayoutTransform>
请注意比例应该倒置,因此 ScaleX 和 ScaleY 将具有这些值:
ScaleX = 1 / scaleX;
ScaleY = 1 / scaleY;