Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Modern WPF

Modern WPF

Room metro Tokyo #4 発表資料です。

KanColleViewer の開発ネタ放出と、de:code のデスクトップ アプリ関連情報のキャッチアップ (のつもり) でした。

Grabacr07

June 02, 2014
Tweet

More Decks by Grabacr07

Other Decks in Programming

Transcript

  1. Subject • 目的 − KanColleViewer で得たデスクトップ / WPF ネタの放出 −

    de:code でのデスクトップ アプリに関するセッションのキャッチアップ • ゴール − モダンな UI を持つ WPF アプリの開発手法を知る − Windows 8 / 8.1 時代の WPF アプリとは何かを知る
  2. Self Introduction • Work − 拝承業者? (メーカー系 SIer 所属エンジニア) −

    C# + WPF (Windows Client Application 開発) • Private activity − Web: http://grabacr.net/ − Twitter: @Grabacr07 (ぐらばく) − めとべや東京勉強会スタッフ − Microsoft MVP for Visual C# (2014/04 ~)
  3. KanColleViewer • Windows Desktop app − .NET Framework 4.5 −

    Visual C# + WPF • 艦これ プレイングツール Internet Explorer Shell + FiddlerCore • 2013/12 公開 (約 5 ヶ月) − 1,650,000 downloads − Blog は Azure Web Sites へ移行 thanks @guitarrapc_tech
  4. KanColleViewer • 常にエゴサーチ (twitter) − メンタル鍛えられます • ユーザーの反応 − 機能に対する反応・要望

    − UI に対する反応・要望 • デベロッパーの反応 − 「この見た目どうやって作んの」
  5. How to: Modern Window • Window system 2 つの領域からなる Nonclient

    Area (非クライアント領域) • ウィンドウの枠 • サイズ変更 • 移動 • キャプション ボタン (最小化・最大化・閉じる) • アイコン • タイトル • システム メニュー 描画・管理: OS のウィンドウ マネージャー Client Area (クライアント領域) • アプリケーションのコンテンツ 描画・管理: アプリケーション
  6. How to: Modern Window • WindowStyle.None − 非クライアント領域を削除 − 標準ウィンドウの動作を

    エミュレートするロジックが必要 Nonclient Area (非クライアント領域) • ウィンドウの枠 • サイズ変更 • 移動 • キャプション ボタン (最小化・最大化・閉じる) • アイコン • タイトル • システム メニュー 描画・管理: OS のウィンドウ マネージャー 要自作 <Window WindowStyle="None" … />
  7. How to: Modern Window • WindowStyle.None − 非クライアント領域を削除 − 標準ウィンドウの動作を

    エミュレートするロジックが必要 − 使いどころは ▫ スプラッシュ画面 ▫ デスクトップ ウィジェット等 <Window WindowStyle="None" … /> ウィンドウ枠・サイズ変更の必要なし キャプション バー必要なし (ウィンドウ全体でドラッグできる)
  8. Excursus: Splash Screen • なる早で出したいスプラッシュ画面 画像のビルド アクションを “SplashScreen” に •

    または、SplashScreen class で Show(bool) • WPF の Application インスタンス が生成される前に表示される • ネイティブ コードを使っている • つまり、表示されるまでが早い!
  9. Excursus: Splash Screen • 画像とウィンドウの両方を出す (Blend for Visual Studio のケース)

    − まず、画像で素早く出す − 次に、本格的 (?) なのを出す ▫ ローカライズされたもの ▫ アニメーションも可 (Office など)
  10. How to: Modern Window • WindowStyle.None − 非クライアント領域を削除 − 標準ウィンドウの動作を

    エミュレートするロジックが必要 − 使いどころは ▫ スプラッシュ画面 ▫ デスクトップ ウィジェット等 <Window WindowStyle="None" … /> @CST_negi 氏の作品 https://github.com/NegishiTakumi/ARiALauncher
  11. How to: Modern Window • Windows API Code Pack (2009

    ~) Windows Vista / 7 で追加された機能のマネージ ラッパー − Application service (recovery, battery, …) − Task bar (progress bar, jump list, …) .NET Framework 4.0 で BCL 入り − Shell (dialog, window chrome, …) − Etc…
  12. How to: Modern Window • Windows API Code Pack (2009

    ~) Windows Vista / 7 で追加された機能のマネージ ラッパー − Application service (recovery, battery, …) − Task bar (progress bar, jump list, …) .NET Framework 4.0 で BCL 入り − Shell (dialog, window chrome, …) − Etc…
  13. How to: Modern Window • Windows API Code Pack (2009

    ~) Windows Vista / 7 で追加された機能のマネージ ラッパー − Application service (recovery, battery, …) − Task bar (progress bar, jump list, …) .NET Framework 4.0 で BCL 入り − Shell (dialog, window chrome, …) − Etc…
  14. How to: Modern Window • WindowChrome class − Window API

    Code Pack -> .NET Framework 4.5 で BCL へ − クライアント領域を拡張 非クライアント領域を覆うように拡張する ▫ ウィンドウ フレームに WPF の コンテンツを含めることが可能 ▫ リサイズ・キャプション領域で システム本来の動作を維持 Nonclient Area (非クライアント領域) • ウィンドウの枠 • サイズ変更 • 移動 • キャプション ボタン (最小化・最大化・閉じる) • アイコン • タイトル • システム メニュー ※ WindowChrome がやってくれるもの
  15. キャプション バーと 認識させるサイズ How to: Modern Window • WindowChrome class

    CaptionHeight property サイズ変更枠と 認識させる太さ ResizeBorder Thickness property サイズ変更グリップ の動作の方向 ResizeGrip Direction attached property
  16. How to: Control library • WPF カスタム コントロール ライブラリ −

    カスタム コントロール&スタイル群 − 別アプリでも同じ外観を再現できる ライブラリ (アセンブリ) を参照し、App.xaml の ResourceDictionary でマージするだけ <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="pack://application:,,,/MyControlLibrary;component/Styles/Controls.xaml" /> <ResourceDictionary Source="pack://application:,,,/MyControlLibrary;component/Styles/Icons.xaml" /> <ResourceDictionary Source="pack://application:,,,/MyControlLibrary;component/Themes/Dark.xaml" /> <ResourceDictionary Source="pack://application:,,,/MyControlLibrary;component/Themes/Accents/Purple.xaml" /> </ResourceDictionary.MergedDictionaries>
  17. How to: Control library • WPF カスタム コントロール ライブラリ −

    カスタム コントロール&スタイル群 − 別アプリでも同じ外観を再現できる ライブラリ (アセンブリ) を参照し、App.xaml の ResourceDictionary でマージするだけ − 使うブラシ定義は統一しておくとよい Normal 時、Active 時、非 Active 時、など <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="pack://application:,,,/MyControlLibrary;component/Styles/Controls.xaml" /> <ResourceDictionary Source="pack://application:,,,/MyControlLibrary;component/Styles/Icons.xaml" /> <ResourceDictionary Source="pack://application:,,,/MyControlLibrary;component/Themes/Dark.xaml" /> <ResourceDictionary Source="pack://application:,,,/MyControlLibrary;component/Themes/Accents/Purple.xaml" /> </ResourceDictionary.MergedDictionaries>
  18. How to: Control library • WPF カスタム コントロール ライブラリ −

    カスタム コントロール&スタイル群 − 別アプリでも同じ外観を再現できる ライブラリ (アセンブリ) を参照し、App.xaml の ResourceDictionary でマージするだけ − 自分で作ってるアプリのブランド化 社内向けツールとかも <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="pack://application:,,,/MyControlLibrary;component/Styles/Controls.xaml" /> <ResourceDictionary Source="pack://application:,,,/MyControlLibrary;component/Styles/Icons.xaml" /> <ResourceDictionary Source="pack://application:,,,/MyControlLibrary;component/Themes/Dark.xaml" /> <ResourceDictionary Source="pack://application:,,,/MyControlLibrary;component/Themes/Accents/Purple.xaml" /> </ResourceDictionary.MergedDictionaries>
  19. Elysium • お手軽モダン UI ライブラリ これ使うだけでそれっぽく見える − http://elysium.codeplex.com/ − Zune

    風コントロール・スタイル群 再現度はあまり高くない… − Visual Studio 2010 or 2012 が必要
  20. Elysium • お手軽モダン UI ライブラリ これ使うだけでそれっぽく見える − http://elysium.codeplex.com/ − Zune

    風コントロール・スタイル群 再現度はあまり高くない… − インストーラーに弾かれる VS2010 or 2012 が必要って言われる − 独自のトースト通知システム Windows 7 でも通知できるが…
  21. for the Tablet PC…? • Windows 8 と様々なタブレット PC の登場

    例のソフトウェア、 Windows 8 でも動くよね? 既に動作確認は取れております タブレット PC で表示が狂う件 大変申し訳ございません早急に 調査し対応致しますので今暫く お待ち頂きますよう宜しくお願
  22. for the Tablet PC…? • Windows 8 と様々なタブレット PC の登場

    例のアプリ、 Windows 8 でも動くよね? 既に動作確認は取れております タブレット PC で表示が狂う件 大変申し訳ございません早急に 調査し対応致しますので今暫く お待ち頂きますよう宜しくお願 高 DPI 環境で表示不良
  23. for the Tablet PC…? • Windows 8 と様々なタブレット PC の登場

    − ディスプレイの小型化 + 高精細化 TABLET / PC SIZE RESOLUTION PPI Surface Pro 2 10.6 inch Full-HD (1920 x 1080) 208 ppi 0.122 mm Surface Pro 3 12 inch Quad-HD (2160 x 1440) 216 ppi 0.117 mm MacBook Pro (Retina) 13.3 inch WQXGA (2560 x 1600) 227 ppi 0.112 mm ThinkPad 8 8.3 inch Full-HD (1920 x 1080) 265 ppi 0.096 mm 高 DPI 環境の標準化 物理的な 1 ドット サイズ
  24. What is DPI? • 今更ですが… • Dots Per Inch −

    1 インチの幅でどれだけのドットを表現できるか − Windows では 1 インチ = 96 pixel − 100 % (96 dpi)、125 % (120 dpi)、150 % (144 dpi) などの設定 [コントロール パネル] -> [デスクトップのカスタマイズ] -> [テキストやその他の項目の大きさの変更] 96 dpi 100 x 50 px 144 dpi 150 x 75 px 96 dpi 100 x 50 px 144 dpi 150 x 75 px
  25. High DPI Issues • UI 要素やテキストが切れる • フォント サイズ /

    レイアウトが不適切になる • UI 要素がぼやける • 座標空間の位置調整が不適切で、入力に影響する 狙った場所にドラッグ&ドロップできなくなったり • 全画面表示のアプリケーションが部分的にしかレンダリングされない 全画面表示のゲームなどで見られる • etc...
  26. DPI-aware application • Win32 application − マニフェストで <dpiAware>True</dpiAware> 宣言 −

    GetDeviceCaps 関数 GetSystemMetrics 関数 SystemParametersInfo 関数 • Windows Forms application − AutoScaleMode プロパティを Dpi に − 開発環境の DPI を記憶
  27. DPI-aware application 96 dpi 環境 (100 %) 144 dpi 環境

    (150 %) • DPI を考慮すると スケーリングされて意図した外観に スケーリングされて サイズが変わってる
  28. DPI Virtualization and Scaling • DPI 仮想化機能 − DPI-unaware applications

    のための救済措置 − Windows Vista で導入 − DPI 設定に合わせて自動的に拡大 96 dpi で画面表示領域外にレンダリングされ、 DWM が拡大して表示 − ぼやける (重要) このチェックを 外した状態
  29. DPI Virtualization and Scaling • ぼやける ただ拡大しているだけなので… 96 dpi 環境

    (100 %) 144 dpi 環境 (150 %) 拡大しただけなので サイズは変わってない
  30. Device Independent Pixel • DIP (デバイス非依存ピクセル) − Direct2D, WPF など

    − 環境の DPI 設定に関わらず 1 dip = 1/96 inch とする − コントロールやフォントのサイズは全て DIP で指定する 開発者が DPI を意識して座標やサイズの計算をする必要がない! − DPI 仮想化が効かない (仮想化する必要がない) − WPF ->「解像度およびデバイスに依存しないグラフィックス」
  31. Device Independent Pixel (WPF) • ぼやけない そのための特別なコードも必要なし 96 dpi 環境

    (100 %) 144 dpi 環境 (150 % のサイズで描画) DIP なので サイズ変わってない
  32. Per-Monitor DPI • モニターごとにスケーリング Primary: 10.6” Tablet (1920 x 1080)

    Secondary: 24” Display (1920 x 1200) 144 dpi (150 %) 96 dpi (100 %)
  33. DPI Awareness Level • DPI-unaware applications − 高 DPI 環境非対応、スケーリングなし

    − 一応 DPI 仮想化は効くけど、品質はお察しレベル • System DPI-aware applications − スケーリングされるので、高 DPI 環境でも表示できる − Windows 8.1 で異なる DPI のディスプレイに移動すると仮想化されてしまう • Per-Monitor DPI-aware ← New! − Windows 8 までの環境で、高 DPI 環境でも表示できる − Windows 8.1 で異なる DPI のディスプレイに移動しても表示できる Windows Forms WPF Windows Store apps
  34. Per-Monitor DPI + WPF • ひつようなもの − マニフェスト Per-Monitor DPI

    に対応していることを宣言 <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"> <dpiAware>True/PM</dpiAware> </asmv3:windowsSettings> </asmv3:application> dpi-Aware 値 効果 False High DPI 対応してません True High DPI 対応してます (Per-Monitor DPI は無理) Per-Monitor Per-Monitor DPI 対応してます (Windows Vista ~ 8 では False) True/PM Per-Monitor DPI 対応してます (Windows Vista ~ 8 では True)
  35. Per-Monitor DPI + WPF • ひつようなもの − MonitorFromWindow 関数 指定したウィンドウがどのモニターに属するかを取得

    − GetDpiForMonitor 関数 (Windows 8.1 で追加) 指定したモニターの DPI を取得 − WM_DPICHANGED メッセージ (Windows 8.1 で追加) DPI が変更されたとき (ディスプレイをまたいだときなど) に飛んでくる
  36. Conclusion • モダンな UI を持つ WPF アプリの開発手法 − 非クライアント領域の削除方法 ▫

    WindowChrome class ▫ WindowStyle 用途に応じて使い分け − WPF カスタム コントロール ライブラリ • Windows 8 / 8.1 時代の WPF アプリ − デスクトップ アプリの High DPI 対応は、もはや必須 − WPF は何もしなくても対応済み、ただし Per-Monitor DPI は対応が必要
  37. Conclusion • WPF アプリのここがつらい − 配布プラットフォームがない ▫ ので、Azure 課金地獄っぽい 酷い日だと

    Azure のデータ転送量 1 日 20 GB とか ▫ とりあえず、バイナリのみ GitHub に置いて対応中 − 広告プラットフォームがない ▫ 野良アプリだと収益化が難しい ▫ やるとしたら、インストーラーに何かバンドルするとか