Windows Formでの高DPI対応

高DPI (High DPI)

Windowsでは10.6インチで1920x1080 (208 dpi) のときは表示スケール150%にするとされており、150%や200%表示スケールのノートPCが高DPIデバイスと呼称されていることから、およそ200dpiを超えるのが高DPIとされているようです。高 DPI と Windows 8.1 | Microsoft Learn

DPI認識モード (DPI Awareness Mode)

モード 表示状態
DPI未対応
(DPI Unaware)
つねに96dpi (100%) で描画されます。よってこれと異なるDPIで実行されると、ぼやけて表示されます。
システムDPI対応
(System DPI Awareness)
ユーザーがサインインした時点のプライマリ接続モニターのDPIで描画されます。よってこれと異なるDPIで実行されると、ぼやけます。
Per-Monitor および Per-Monitor V2のDPI対応
(Per-Monitor and Per-Monitor V2 DPI Awareness)
DPIが変更されるたびに描画し直すことで、ぼやけない。
DPI 認識モード - Windows での高 DPI デスクトップ アプリケーションの開発 - Win32 apps | Microsoft Learn

Per-MonitorのDPI対応

DPIはアプリケーションの実行中にも変更されることがあります。たとえばDPIの異なるディスプレイへのアプリケーション ウィンドウの移動、DPIの異なるディスプレイの接続や解除、それにDPIの異なる環境へのリモート接続などがあります。

Per-Monitor V2 (PMv2)

Per-Monitor V2はPer-Monitorと比較して、

  • DPIの変更がトップレベルだけではなく、子HWNDにも通知される
  • 非クライアント領域、共通コントロールのテーマ描画ビットマップ (comctl32 V6)、ダイアログが適切にスケーリングされる

のような相違があります。Per-Monitor および Per-Monitor (V2) の DPI 対応 - Windows での高 DPI デスクトップ アプリケーションの開発 - Win32 apps | Microsoft Learn

認識モードの確認

個々のアプリケーションが高DPIに対応しているか否かは、タスクマネージャーでも確認できます。タスク マネージャーでアプリのDPI対応を確認可能 ~「Windows 10 19H1」Build 18262 - 窓の杜 樽井秀人 (2018/10/18)

Per-Monitor V2の宣言方法

Windows 10 Creators Update以降かつ.NET Framework 4.7以降を対象としたWindows Formアプリケーションには、以下の方法でPer-Monitor V2対応であると宣言できます。高 DPI サポート - Windows Forms .NET Framework | Microsoft Learn

高DPI対応であると宣言すると自動でスケーリングされなくなるため、ぼやけて表示されることはなくなります。しかしそのとき明示的にスケーリングの処理をしないと、DPIに適合した表示となりません。Windows での高 DPI デスクトップ アプリケーションの開発 - Win32 apps | Microsoft Learn

Per-Monitor V2ならば、一部のコントロールが適切に自動でスケーリングされます。Per-Monitor および Per-Monitor (V2) の DPI 対応 - Windows での高 DPI デスクトップ アプリケーションの開発 - Win32 apps | Microsoft Learn

アプリケーション構成ファイル (App.config)

App.configファイルの<configuration>要素に

<System.Windows.Forms.ApplicationConfigurationSection>
    <add key="DpiAwareness" value="PerMonitorV2" />
</System.Windows.Forms.ApplicationConfigurationSection>

を追記します。DpiAwareness - Windows フォームの add 構成要素 - .NET Framework | Microsoft Learn

個別に無効にしたい対象があるならば、それも追記します。

<add key="EnableWindowsFormsHighDpiAutoResizing" value="false" />
<add key="CheckListBox.DisableHighDpiImprovements" value="true" />
<add key="DataGridView.DisableHighDpiImprovements" value="true" />
<add key="Toolstrip.DisableHighDpiImprovements" value="true" />

アプリケーション マニフェスト (Application manifest)

アプリケーション マニフェストを作成し、それに

<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
        <!-- Windows 10 -->
        <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
    </application>
</compatibility>

と記述します。このようにWindows 10サポートと指定しないと、システムDPI対応となります。また実行ファイルAppName.exeのフォルダに、同名の設定ファイルAppName.exe.configが配置されていないと、DPI対応となりません。

<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
        <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
        <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
    </windowsSettings>
</application>

を記述します。 supportedOS - アプリケーション マニフェスト - Win32 apps | Microsoft Learn 常に管理者としてアプリケーションを実行させるには?[C#、VB、VS 2008] - @IT 一色政彦 (2009/12/17)

このようにdpiAwarenessを指定しないと、マニフェスト内にPerMonitorV2がないと警告されます。 dpiAwareness - アプリケーション マニフェスト - Win32 apps | Microsoft Learn c# - Microsoft store certification fails due to DPI awareness - Stack Overflow

要素 意味
dpiAware true システムDPI対応
true/pm Windows 8.1より前ならばシステムDPI、それ以降ならばPer-Monitor対応
dpiAwareness permonitor Per-Monitor対応
permonitorv2 Windows 10 Creators Update (1703) より前ならば無効、それ以降ならばPer-Monitor V2対応

Windows 10 Anniversary Update (1607) 以降ではdpiAwarenessがあるときはdpiAwareは無視されるため、それ以降しか想定しないならばdpiAwarenessだけを指定します。

DataGridViewの対応

Per-Monitor V2でもDataGridViewは自動でスケーリングされないため、明示的な処理が必要です。

protected override void OnDpiChangedAfterParent(EventArgs e)
{
    base.OnDpiChangedAfterParent(e);

    //Font = Parent.Font;
    OnFontChanged(EventArgs.Empty);
}

Fontへの設定では初回はFontChangedが発生しないため、OnFontChanged()を呼ぶのが確実です。

複数の技術系サイトから、まとめて検索