2016/05/29

WPFのPer-Monitor DPIサポート(その2)

少し前になりますが、.NET Framework 4.6.2 PreviewでWPFのプラットフォームによるPer-Monitor DPI機能が試せるようになっています。といっても普通に動きすぎて特記することもなく、またプレビュー段階であまり深入りするのも意味がある気がしないので、簡単にまとめてみます。


1. 概要


まずはWPF-SamplesにあるDeveloper Guideから。View Rawでダウンロードできます。
これを読むと、試すには以下が条件になっています。
  • .NET Framework 4.6.2 Previewのインストール
  • Windows 10限定(Windows 8.1については記載なし)
方法としては、基本的にapp.manifestのdpiAwareをtrue/PMにしておけば終わりです。WPFのレイアウトシステムに乗ったUIであれば、他に何も要りません。それでは対応できない場合のために個別に救済策が用意されていますが、引っ掛かることがなければ使う機会はないと思います。

DPI変化は、VisualのレベルでOnDpiChangedメソッドが用意されているので、これをオーバーライドすることで感知できます。さらにWindowやImageにはDpiChangedイベントが追加されているので、これでも感知できます。

細かくは、DpiScaleInfoはDpiScaleに名前が変わりました。またDpiChangedイベント用にDpiChangedEventHandlerとDpiChangedEventArgsが追加されたので、これだけから新旧のDPIを取得できます。

[追記] VisualTreeHelper.GetDpiメソッド

.NET Framework 4.6.2で追加されたVisualTreeHelper.GetDpiメソッドで対象VisualのDpiScaleを簡単に取得することができますが、これが正確に機能するのはAnniversary Update以降の場合です。それ以前の場合は従来どおり自前の方法で取得する必要があります。

2. テスト


簡単に動作をテストするアプリを書きました。

気づいた点を挙げると、
  • 実際のスケーリングとOnDpiChangedやDpiChangedは結びついていない。つまり、OnDpiChangedをオーバーライドして変えてもスケーリングは操作できない。
  • VisualTreeHelper.SetRootDpiを実行するとVisualTreeで波及的にOnDpiChangedを実行させることができるが、これも実際のスケーリングとは関係しない。
  • WM_DPICHANGEDメッセージを受信したときにhandledをtrueにするとスケーリングを抑止できる。つまり、実行時にスケーリングさせないよう動作を変えることも可能。
実はWindows 8.1に対応させる気があるかどうか分からないので、保険としてWM_DPICHANGEDを受けてスケーリングを直接起こさせる手もあるかと思ったのですが、そうは行かないようで。

一応、このアプリのレポジトリ。
何にせよ、すべては現段階での話です。

2 コメント :

匿名 さんのコメント...

これを読むと、試すには以下が条件になっています。
.NET Framework 4.5.2 Previewのインストール


4.6.2だと思います

EMO さんのコメント...

ご指摘ありがとうございます。書き間違えました。直します。