PicSumという画像ビューアを作っています。
別に画像ビューアでなくてもよいのですが、長いこと開発しているうちにSystem.Windows.Formsとは思えないようなUIになったため、色々なところを紹介させていただきます。
タイトルバーにUIを組み込む。
UWPではタイトルバーをカスタマイズできるらしいとのことですが、System.Windows.Forms.Formでは本来できません。
タイトルバーを表示しないウィンドウにすることはできますが、それだと最大化ボタンなどが使用できず、仮にそれを独自実装しても一般的なウィンドウと同じ挙動は再現できません。
どうやって実現しているか?
Win32 MessageのWM_NCCALCSIZEを書き換えて実現しています。
方法を見つけるまでは大変でしたが突き詰めれば以下の通りだけです。
protected override void WndProc(ref Message m)
{
if (m.Msg == WinApiMembers.WM_NCCALCSIZE)
{
var nccsp = (WinApiMembers.NCCALCSIZE_PARAMS)Marshal.PtrToStructure<WinApiMembers.NCCALCSIZE_PARAMS>(m.LParam);
nccsp.rgrc0.left += 8;
nccsp.rgrc0.right -= 8;
nccsp.rgrc0.bottom -= 8;
Marshal.StructureToPtr(nccsp, m.LParam, false);
return;
}
else if (m.Msg == WinApiMembers.WM_NCPAINT ||
m.Msg == WinApiMembers.WM_NCACTIVATE ||
m.Msg == WinApiMembers.WM_NCHITTEST ||
m.Msg == WinApiMembers.WM_SETREDRAW ||
m.Msg == WinApiMembers.WM_DPICHANGED ||
m.Msg >= WinApiMembers.WM_DWM_FIRST && m.Msg <= WinApiMembers.WM_DWM_LAST)
{
// WM_NCCALCSIZEを処理すると最大化ボタン等が反応しないので、以下の処理で対処する。
var dwmHandled = WinApiMembers.DwmDefWindowProc(
m.HWnd, m.Msg, m.WParam, m.LParam, out var result);
if (dwmHandled == 1)
{
m.Result = result;
return;
}
}
base.WndProc(ref m);
}
Webブラウザのようなタブ操作
タブは後述のファイルリストと同様にPaintイベントで全て描画しています。
それをドラッグアンドドロップで操作しているように描画し、Webブラウザのタブのように切り離しや結合を実現しています。

オリジナルのリスト
デフォルトのListBoxやListViewでは機能やカスタマイズ性が貧弱なため、Paintイベントで全てを描画しています。
これは以下の数値がわかれば実装できます。もちろんスクロール位置も。
ワイドなコンボボックス
普通のコンボボックスは縦に一列だけですので、項目が増えるとスクロールする必要があります。
そこでグリッドのように項目を配置して、一度に目にする項目の数を増やしています。(賛否あるかもしれませんが)
これは上記のファイルリストを変形して実装しています。

画像ファイルの切り替え処理の順番
画像ファイルの読み込み処理は可能な限り高速な方法を採用しています。
が、読み込み処理を非同期化するのは当然としても、素早く切り替えた際にユーザー体験を損なわないため3段階で描画しています。
これらはどの段階でも後続の処理を優先して、いつでもキャンセルできるようにしています。
最後に
興味のある方は Microsoft Store からぜひご利用ください。
Microsoft Store PicSum




