マルチモニタ環境でセカンダリディスプレイへウィンドウを表示し、初期状態でフルスクリーン表示する方法がうまくいかず、位置がずれたり表示が壊れたりしたため、どうすべきか調べました。
ウィンドウを表示するタイミングは、メインウィンドウのボタン押下時です。その時にフルスクリーン表示したいウィンドウを生成しようとチャレンジしてました。
基本的には、以下の流れで処理できるようです。
// ウィンドウの生成
var win = new FullWindow();
// セカンダリディスプレイの左上をウィンドウの位置とする
// monitorはディスプレイ番号でセカンダリを表すものとする
win.Left = System.Windows.Forms.Screen.AllScreens[monitor].WorkingArea.X;
win.Top = System.Windows.Forms.Screen.AllScreens[monitor].WorkingArea.Y;
// ウィンドウの表示
win.Show();
// ウィンドウのフルスクリーン表示
win.WindowState = WindowState.Maximized; // ウィンドウをフルスクリーン表示にする
win.WindowStyle = WindowStyle.None; // ウィンドウの境界線スタイルを無しにする
win.ShowInTaskbar = false; // タスクバーを非表示にする
ところがこれだけですと、プライマリディスプレイでは簡単に動いたのですが、どうもプライマリディスプレイが高DPIモニタであることが影響して、違うディスプレイに表示されたり、フルスクリーン表示が壊れ、中途半端なサイズのウィンドウが表示される、という不思議な現象に遭遇しました。
そのため、問題点は2点あると予想しました。
- ウィンドウ位置の高DPI対応しないといけない
- ウィンドウのフルスクリーン表示設定タイミングを変更することが必要
いろいろ悩んだ挙句ですが、問題なのはプライマリが高DPIであることに限定し、win.Leftとwin.Topを設定する際に、プライマリのdpiを計算することにしました。なお、デフォルトのdpiは96であると仮定しています。
double dpi = PresentationSource.FromVisual(Application.Current.MainWindow).CompositionTarget.TransformFromDevice.M11;
win.Left = (int)((double)Screen.AllScreens[monitor].WorkingArea.X * dpi);
win.Top = (int)((double)Forms.Screen.AllScreens[monitor].WorkingArea.Y * dpi);
また、フルスクリーン表示の設定をするタイミングもLoadedイベントにすれば解決するかと思ったのですが、どうも違うようでしたので、SourceInitializedを使用しました。
win.SourceInitialized += (sender, arg) => {
win.WindowState = WindowState.Maximized; // ウィンドウをフルスクリーン表示にする
win.WindowStyle = WindowStyle.None; // ウィンドウの境界線スタイルを無しにする
win.ShowInTaskbar = false; // タスクバーを非表示にする
};
これらコードは、実際に動かしたものではないですが、手持ちの環境では、こうした対応で、動作を確認できました。