モノトーンの伝説日記

Apex Legends, Splatoon, Programming, and so on...

『WPFでカスタムウィンドウを作るのに人類は奮闘してきた』(カスタムウィンドウ最大化問題) 序章

 HAHAHA。なんでなんやろ,歴史調べたら人々が奮闘してきたのがわかる。

1. この原因を調べるきっかけ。

 これ。

github.com

 結論から言うと解決の道筋は見えました(まだ綺麗に実装し直していない)。

2. 人々の歴史。

 MetroRadiance もそうですが,100% 環境で最大化した場合,外側に 8epx 引っ張られるので,それを補正する xaml

<Trigger Property="WindowState" Value="Maximized">
  <Setter Property="BorderThickness" Value="0" />
  <Setter Property="Padding" Value="8" />
</Trigger>

MetroRadiance/Generic.MetroWindow.xaml at a074ff0843d9553798d1ecee016b702a29f6d0c5 · Grabacr07/MetroRadiance · GitHub

 これ,100% 環境でだけ動作するコードなんですよね (100% 以外は余白の大きさが違う)。そしたらやっぱり気になるじゃないですか,回避方法。

2.1 回避方法 1: ハードコード

 currentDpi を取得して margin を決め打ちするハードコード! すばらしいですね,調査する根気。

www.source-weave.com

protected virtual Thickness GetDefaultMarginForDpi()
{
  int currentDPI = SystemHelper.GetCurrentDPI();
  Thickness thickness = new Thickness(8, 8, 8, 8);
  if (currentDPI == 120)
  {
    thickness = new Thickness(7, 7, 4, 5);
  }
  else if (currentDPI == 144)
  {
    thickness = new Thickness(7, 7, 3, 1);
  }
  else if (currentDPI == 168)
  {
    thickness = new Thickness(6, 6, 2, 0);
  }
  else if (currentDPI == 192)
  {
    thickness = new Thickness(6, 6, 0, 0);
  }
  else if (currentDPI == 240)
  {
    thickness = new Thickness(6, 6, 0, 0);
  }
  return thickness;
}

 いやほんとすごいですね。気づいてない不具合だったので,気づけただけでもすごいと思います。

2.2 回避方法 2: インテリジェンス

www.codeproject.com

 すばらしいです。模範解答です。

 これで! OK かと思いきや…… ですよね。

3. やっぱり自動で隠れるタスク バーがひらけない。

 そこで気づいちゃったんですね。感の良い人なら知っているかもしれません。

 以下は 200% で動かしている Visual Studio の最大化ウィンドウの左下部分です (100% ととはちょっと違います)。

f:id:mntone:20200801103817p:plain

 え? どこがどう違うって?

 はい,普通だとその反応が正解ですね。実は,タスクバーが下に設定されている場合,下に 1epx (200% なので 2px) の余白があります。つまり,2.2 で提示した最大化の範囲指定にちょっと手を加えて,自動でタスク バーが隠れる場合,タスクバーのある方向に 1epx の余白を追加してやれば良いんです。

8/1 12:43追記: 1epx ではなく,2px かもしれません。スケーリングにかかわらず (要調査)。

 動きました

まとめ

 WPF のカスタムウィンドウ最大化問題の解決方法は:

  1. WM_GETMINMAXINFO で正しい最大化情報を指定する。
  2. その際,タスク バーが自動で隠れる設定である場合,補正をかけてやる。

 これが正解でした。誰がわかるねんこんなん……

8/2 追記: 実はこの方法,大きな問題がありまして……

 タスクバーの移動に対応できない/(^o^)\

 ということで新しい記事書いてます。

mntone.hateblo.jp

おまけ

 ここからは興味ある人向けの話題。

 WPF はすでにオープンソースで開発されていますが,WM_GETMINMAXINFO 周りの挙動を追ってみました。

mstdn.jp

 他にも WM_GETMINMAXINFO を操作する部分があるかもしれませんが,特に変なことしていないと言うことなので,OS からの挙動っぽいですねこれ。