Roe*_*ngs 10 .net c# highdpi winforms dpi-aware
所以我们有这个奇怪的问题.我们的应用程序是一个C#/ WinForms应用程序.在我们的6.0版本中,我们的应用程序不支持DPI.在我们的6.1版本中,它突然变成了DPI意识.
在6.0版本中,如果您在高DPI中运行它,它使用Windows位图缩放,这很好,因为这不会影响屏幕布局.在6.1版本中,由于它因某种原因而成为DPI识别,因此用户界面受到严重破坏.
我们现在无法解决这个问题.我们有数百个屏幕,因此在DPI识别模式下使它们全部正常工作将花费大量时间.
我们已使用SysInternals Process Explorer确认了这一点.在我们的6.0版本中,它显示了Unaware,但在我们的6.1版本中,它最初显示Unaware,但随后更改为System Aware.
后者发生在代码从EXE进入包含所有用户界面代码的程序集DLL中时(我们的EXE基本上是一个非常薄的shell;它实际上只是在我们的表示层程序集上调用一个Controller类.)
我们已确认以下内容:
我们不明白为什么我们的6.1版本突然变成了DPI意识.我们无知还有什么可以看,我们需要一个修复程序,将此版本恢复到DPI unaware模式.它正在阻止我们的发布.非常感谢任何指针.我们愿意在这一点上尝试任何事情.
Jim*_*imi 10
关于本课题中报告的问题:
一个DPI不知道设计的应用程序,依靠Windows虚拟化来扩展其UI内容,突然(虽然经过一些修改,导致次要版本更新) - 并且显然没有可观察到的原因 - 成为DPI-Aware(系统意识).
该应用程序还依赖于app.manifest <windowsSettings>对缺少DPI感知定义的解释,默认(对于向后兼容性)DPI-Unaware.
没有对WPF程序集的直接引用,也没有与DPI相关的API调用.
该应用程序包括第三方组件(可能还包括外部依赖项).
由于DPI-Awareness已经成为UI呈现的一个相关方面,考虑到可用屏幕分辨率的多样性(以及相关的DPI缩放设置),大多数组件生产商已经适应了高DPI,他们的产品是DPI-Aware(DPI更改时的扩展)检测到并使用DPI-Aware程序集(通常根据定义引用WPF程序集,DPI-Aware).
当在项目中(直接或间接)重新引用其中一个DPI-Aware组件时,如果未明确禁用DPI-Awareness,则DPI-Unaware应用程序将成为DPI-Aware.
声明程序集DPI-Awareness的更直接(和推荐)方法是在应用程序清单中明确声明它.
有关Visual Studio 2017之前的应用程序清单设置,请参阅Hans Passant答案:
如何配置应用程序以在具有高DPI设置的计算机上运行
在Visual Studio 2015-Upd.1和Visual Studio 2017中app.manifest,此设置已存在,只需取消注释即可.设置部分:<dpiAware>false</dpiAware>.
<?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"/>
//(...)
<!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher
DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need
to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should
also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config. -->
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">false</dpiAware>
</windowsSettings>
</application>
//(...)
</assembly>
Run Code Online (Sandbox Code Playgroud)
有关更多信息,请参阅这些MSDN文章:
Windows上的高DPI桌面应用程序开发
设置进程的默认DPI感知
另一种方法是使用以下Windows API函数设置进程上下文DPI-Awareness:
Windows 7
SetProcessDPIAware
[DllImport("user32.dll", SetLastError=true)]
static extern bool SetProcessDPIAware();
Run Code Online (Sandbox Code Playgroud)
Windows 8.1
SetProcessDpiAwareness
[DllImport("shcore.dll")]
static extern int SetProcessDpiAwareness(ProcessDPIAwareness value);
enum ProcessDPIAwareness
{
DPI_Unaware = 0,
System_DPI_Aware = 1,
Per_Monitor_DPI_Aware = 2
}
Run Code Online (Sandbox Code Playgroud)
Windows 10,版本1703
SetProcessDpiAwarenessContext()
(当选择Per-Monitor DPI-Awareness时,使用Context_PerMonitorAwareV2)
另请参阅:混合模式DPI扩展和DPI感知API - MSDN
Windows 10,版本1809(2018 年 10月)添加了
一个新的DPI_AWARENESS_CONTEXT:DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED
DPI没有意识到基于GDI的内容质量的提高.此模式的行为与DPI_AWARENESS_CONTEXT_UNAWARE类似,但也可以使系统在高DPI监视器上显示窗口时自动提高文本和其他基于GDI的基元的渲染质量.
使用该GetWindowDpiAwarenessContext()函数检索DPI_AWARENESS_CONTEXTWindow GetThreadDpiAwarenessContext()的DPI_AWARENESS_CONTEXT句柄和当前线程的句柄.然后从结构中GetAwarenessFromDpiAwarenessContext()检索DPI_AWARENESS值DPI_AWARENESS_CONTEXT.
[DllImport("user32.dll", SetLastError=true)]
static extern IntPtr GetWindowDpiAwarenessContext(IntPtr hWnd);
[DllImport("user32.dll", SetLastError=true)]
static extern IntPtr GetThreadDpiAwarenessContext();
[DllImport("user32.dll", SetLastError=true)]
static extern int GetAwarenessFromDpiAwarenessContext(InPtr DPI_AWARENESS_CONTEXT);
[DllImport("user32.dll", SetLastError=true)]
static extern int SetProcessDpiAwarenessContext(ContextDPIAwareness value);
// Virtual enumeration: DPI_AWARENESS_CONTEXT is *contextual*.
// This value is returned by GetWindowDpiAwarenessContext() or GetThreadDpiAwarenessContext()
// and finalized by GetAwarenessFromDpiAwarenessContext(). See the Docs.
enum ContextDPIAwareness
{
Context_Unaware = ((DPI_AWARENESS_CONTEXT)(-1)),
Context_SystemAware = ((DPI_AWARENESS_CONTEXT)(-2)),
Context_PerMonitorAware = ((DPI_AWARENESS_CONTEXT)(-3)),
Context_PerMonitorAwareV2 = ((DPI_AWARENESS_CONTEXT)(-4)),
Context_UnawareGdiScaled = ((DPI_AWARENESS_CONTEXT)(-5))
}
Run Code Online (Sandbox Code Playgroud)
由于DPI-Awareness是基于线程的,因此这些设置可以应用于特定线程.在重新设计用户界面以实现DPI-Awareness时,这可能很有用,让系统在关注更重要的功能时缩放不太重要的组件.
SetThreadDpiAwarenessContext
(与参数相同SetProcessDpiAwarenessContext())
Assemblyinfo.cs
如果引用WPF程序集的第三方/外部组件重新定义了应用程序的DPI-Awareness状态,则可以禁用此自动行为,在项目中插入参数Assemblyinfo.cs:
[assembly: System.Windows.Media.DisableDpiAwareness]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1829 次 |
| 最近记录: |