$30 off During Our Annual Pro Sale. View Details »

Step up WPF

Grabacr07
August 01, 2016

Step up WPF

Metro.cs #2 発表資料

Grabacr07

August 01, 2016
Tweet

More Decks by Grabacr07

Other Decks in Programming

Transcript

  1. WPF を「使う」から
    「使いこなす」へ
    2016/07/15 Metro.cs #2
    Manato KAMEYA (@Grabacr07)

    View Slide

  2. Agenda
    最近の WPF 事情つまみ食い
    ここ 2 ~ 3 年の WPF へのアップデート
    Windows 10 / UWP 時代の WPF の立ち位置とは
    WPF を適切に乗りこなす
    コントロールの選択とカスタム実装の境界線
    ライブラリ化までを見据えた再利用性のある実装

    View Slide

  3. Self Introduction
    亀谷学人 (かめやまなと)
    • 1987年生まれ
    • 仙台出身 / 東京在住
    Windows Study Meeting (まどすた) staff
    Microsoft MVP for Visual Studio and Development Technologies 長いよ。
    • ソフトウェア エンジニア
    • クライアント設計 / C# / XAML
    Twitter: @Grabacr07
    Facebook: manato.kameya
    Blog: http://grabacr.net/

    View Slide

  4. My Apps
    KanColleViewer
    「艦これ」 プレイング ツール
    C# + WPF (.NET Framework 4.6.2)
    SylphyHorn
    仮想デスクトップ ツール
    アクティブ ウィンドウごと移動

    View Slide

  5. State of WPF
    Windows 10, UWP 時代の今
    Classic Desktop とかいわれる
    「従来のデスクトップ」 だったことも…
    Visual Studio “15” では
    オプション扱い?
    XAML というと UWP という風潮 [要出典]

    View Slide

  6. WPF vs UWP
    Feature WPF UWP
    Windows Desktop
    (Simple app)
    ◯ ◯
    Windows Desktop
    (Task tray, IE Shell, Keyhook, …)
    ◯ ✕
    Universal Platform API
    (Live Tile, Cortana, Notifications, …)
    ✕ ◯
    Other Platforms
    (Mobile, Xbox, IoT, HoloLens, …)
    ✕ ◯
    Application distribution
    (Windows Store)
    ✕ ◯

    View Slide

  7. WPF vs UWP
    Feature WPF UWP
    Windows Desktop
    (Simple app)
    ◯ ◯
    Windows Desktop
    (Task tray, IE Shell, Keyhook, …)
    ◯ ✕
    Universal Platform API
    (Live Tile, Cortana, Notifications, …)
    ✕ ◯
    Other Platforms
    (Mobile, Xbox, IoT, HoloLens, …)
    ✕ ◯
    Application distribution
    (Windows Store)
    ✕ ◯
    Windows Desktop に絞るなら WPF のほうがいいよ! (弱気)

    View Slide

  8. デバイスの発展から見た WPF
    Recent trend of WPF (1)

    View Slide

  9. API Overview
    .NET Framework 4.5 以降の WPF
    DPI 関連の改修が多め [独自研究]
    High DPI と Per-Monitor DPI への対応
    WPF はもともと DPI-aware
    DPI を意識しなくてもシステムが良しなに
    デバイス非依存ピクセル (DIP) 単位
    WPF: 96 dpi での 1 px を 1 dip
    Android: 160 dpi での 1 px を 1 dip
    Android の場合は密度非依存ピクセルですが…
    Primary: 10.6” Tablet (1920 x 1080)
    144 dpi (150 %)

    View Slide

  10. High DPI Improvements
    例えば DPI 150 % 環境下において
    Value="1" />

    View Slide

  11. High DPI Improvements
    例えば DPI 150 % 環境下において
    2 px
    2 px 2 px
    1 px

    View Slide

  12. High DPI Improvements
    UseLayoutRounding property
    > MSDN から引用
    https://msdn.microsoft.com/ja-jp/library/system.windows.frameworkelement.uselayoutrounding(v=vs.110).aspx
    レイアウト計算を丸めて、半透明エッジを排除する機能
    DPI 150 % の場合 となるが…
    Round (1.0 px * 150 %) = 2.0 px
    0.25px 0.25px
    1.00 px 1.00 px
    0.25px 0.25px
    Round (1.25) = 1 …?

    View Slide

  13. High DPI Improvements
    .NET Framework 4.6 アプリの場合
    境界線の丸めをうまく処理してくれるようになった
    UseLayoutRounding="true"
    正しく 2 px で描画される
    コード修正必要なし

    View Slide

  14. DPI Scaling
    150 % 環境における DPI スケーリング
    そもそも、Border が 2 px になるのは如何なものか
    Windows の VisualStyle は DPI 150 % でも Border は 1 px
    1 px ではなく 0.99 と指定する
    となり、150 % 環境下でも Border = 1 px を再現可能
    http://mntone.hateblo.jp/entry/2015/06/29/090728
    Round (0.99 px * 150 %) = Round (1.485) = 1 px

    View Slide

  15. Per-Monitor DPI
    モニターごとの DPI スケーリング
    Primary: 10.6” Tablet (1920 x 1080) Secondary: 24” Display (1920 x 1200)
    144 dpi (150 %) 96 dpi (100 %)

    View Slide

  16. Per-Monitor DPI
    モニターごとの DPI スケーリング
    Windows 8.1 で追加された機能 (約 3 年前…)
    モニターをまたいだときにウィンドウの DPI 変更
    アプリ側が非対応の場合、単純な拡縮処理されてしまう

    View Slide

  17. Per-Monitor DPI
    これくらいの差
    Per-Monitor DPI aware (左)
    DPI 変更をアプリ側検知
    自前でスケーリング処理
    System DPI aware (右)
    DPI 変更は OS 任せ
    OS による単純な拡縮処理

    View Slide

  18. Per-Monitor DPI aware
    WPF での従来の対応方法
    ウィンドウ プロシージャー書いて WM_DPICHANGED
    MSDN の解説だと C++ コードが出てくる…
    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
    if (msg == (int)WindowsMessages.WM_DPICHANGED)
    {
    var dpiX = wParam.ToLoWord();
    var dpiY = wParam.ToHiWord();
    this.ChangeDpi(new Dpi(dpiX, dpiY));
    handled = true;
    }
    return IntPtr.Zero;
    }

    View Slide

  19. Per-Monitor DPI aware
    .NET Framework 4.6.2 Preview
    DpiChanged イベントが追加された
     Window, HwndSource, Image
    public partial class MainWindow : Window
    {
    public MainWindow()
    {
    InitializeComponent();
    }
    protected override void OnDpiChanged(DpiScale oldDpi, DpiScale newDpi)
    {
    base.OnDpiChanged(oldDpi, newDpi);
    }
    }
    ScaleTransform を使って
    ウィンドウの中身を拡縮
    したりするとよいとおもう

    View Slide

  20. Windows 10 の発展から見た WPF
    Recent trend of WPF (2)

    View Slide

  21. Windows Bridge
    for Classic Desktop App
    Windows 10 Anniversary Update (Insider Preview Build 14316 or later)
    デスクトップ アプリを UWP にするやつ

    View Slide

  22. Windows Bridge
    Desktop App Converter
    Win32 / .NET app を UWP パッケージ化する
    あくまでパッケージ化するだけで、中身はそのまま
    .msi をサイレント モードで動作させ、展開されたファイルを .appx へ
    MSI AppX
    ※ //build/ 2016 資料から引用

    View Slide

  23. View Slide

  24. WPF is UWP
    WPF in AppX は何者か
    UWP アプリ = Universal Platform 上で動くアプリ
    (つまり、対応デバイスの種類や数は関係ない)
    WPF in AppX = Windows 10 Desktop に対応した UWP アプリ
    参考: UWP という表現と Desktop App Converter について
    https://blogs.msdn.microsoft.com/shintak/2016/05/25/uwpanddesktopappconverter/

    View Slide

  25. Bridge to the UWP
    UWP アプリへの 5 つのステップ
    Convert Enhance Extend Migrate Expand

    View Slide

  26. Desktop App Converter
    Bridge to the UWP
    UWP アプリへの 5 つのステップ
    将来的に UWP アプリへ移行してほしい (って Microsoft が言ってる)
    Desktop App Converter は Step 2 までを実現するツール
    Convert Enhance Extend Migrate Expand

    View Slide

  27. WPF vs UWP (2016)
    Feature WPF UWP
    Windows Desktop
    (Simple app)
    ◯ ◯
    Windows Desktop
    (Task tray, IE Shell, Keyhook, …)
    ◯ ✕
    Universal Platform API
    (Live Tile, Cortana, Notifications, …)
    ◯ ◯
    Other Platforms
    (Mobile, Xbox, IoT, HoloLens, …)
    ✕ ◯
    Application distribution
    (Windows Store)
    ◯ ◯

    View Slide

  28. WPF vs UWP (2016)
    Feature WPF UWP
    Windows Desktop
    (Simple app)
    ◯ ◯
    Windows Desktop
    (Task tray, IE Shell, Keyhook, …)
    ◯ ✕
    Universal Platform API
    (Live Tile, Cortana, Notifications, …)
    ◯ ◯
    Other Platforms
    (Mobile, Xbox, IoT, HoloLens, …)
    ✕ ◯
    Application distribution
    (Windows Store)
    ◯ ◯
    Windows Desktop に絞るなら WPF のほうがいいよ! (強気)

    View Slide

  29. Bridge to the UWP
    Step 2: Enhance
    Desktop app 内部から
    UWP の API を呼び出し
    ライブ タイルのサポート
    Actionable Notifications (トースト通知操作)
    Cortana
    他いろいろ
    Universal App Package
    Universal Windows API
    Classic Windows App

    View Slide

  30. Bridge to the UWP
    Step 3: Extend
    UWP App Service や
    Background tasks 等の機能追加
    UWP App と Desktop App の共存
     エントリー ポイントは UWP App 側へ
     両者は App Service で通信
    フロントエンドを XAML / コアを Win32 とか
    File Picker UI
    Universal App Package
    Universal Windows App
    Classic Windows App

    View Slide

  31. WPF in Windows 10
    デバイスの多様化への対応
    特に High DPI・Per-Monitor DPI 周り
    他、タッチ キーボード動作改善とか
    WPF も UWP へ
    Windows 10 Desktop 向けの UWP ㌠
    パッケージ化してストア配布しよう

    View Slide

  32. WPF と健全なお付き合いをするために
    Riding out the WPF

    View Slide

  33. Modern UI World
    こういうの作りたい
    インストーラーでこれ

    View Slide

  34. XAML Platform
    要件に対する適切な選択
    表現力や柔軟性が非常に高い UI フレームワーク
    ControlTemplate, DataTemplate, Style, Trigger, Theme, Resource, …
    数ある選択肢からもっとも要件にマッチした選択が必要
    マウス オーバーと
    クリック時に
    全体の色を変える…
    円と矢印、
    押しやすいように
    Margin 広めで…
    クリックすると
    前の画面へ…
    ビットマップ画像?
    それともベクター?
    これを
    どう作るか?

    View Slide

  35. Control Authoring
    新しいコントロールを作成しないために
    WPF の豊富なカスタマイズ機能
    リッチ コンテンツ
    ボタン (に限らず)
    中身何でも置ける
    テンプレート
    リスト項目でも何でも
    自由なデータ表示方法
    スタイル・トリガー
    再利用可能な外観や
    動作カスタマイズ

    View Slide

  36. Control Authoring
    新しいコントロールを作成しないために
    外観ではなく機能に着目すべき

    View Slide

  37. Control Authoring
    新しいコントロールを作成しないために
    外観ではなく機能に着目すべき
    ListBox
    ItemsControl TabControl
    外観が同じでも、
    機能要件が異なる
    テンプレートがあれば
    外観はどうとでもなる
    重要なのは機能のほう

    View Slide

  38. Control Authoring
    外観ではなく機能に着目する
    コントロールの外観はいくらでも変更できる
     外観はコントロールの選択基準にならない
    コントロールは機能で選ぶ
    必要な機能
    • クリックに反応 (Click 相当イベント)
    • 中に何かを置く (リッチ コンテンツ)
    ボタンだこれ
    ※ 要求を満たす機能を
    持つものがなければ作る

    View Slide

  39. Original Control
    Case study: ツイート入力ボックス
    これらの機能を満たす既成コントロールは存在しない
     新しいコントロールを作成する必要がある
    必要な機能
    • テキスト入力 (文字列入力)
    • 残り文字数カウント (連動するカウンター)
    • ツイート送信ボタン (Click 相当イベント)

    View Slide

  40. User Control
    UserControl 型から派生するコントロール
    最もシンプルな方法
    • TweetInputBox1.xaml





    Margin="4" />

    View Slide

  41. User Control
    UserControl 型から派生するコントロール
    最もシンプルな方法
    • TweetInputBox1.xaml.cs
    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
    nameof(Text), typeof(string), typeof(TweetInputBox), new PropertyMetadata(default(string), TextPropertyChangedCallback));
    public string Text
    {
    get { return (string)this.GetValue(TextProperty); }
    set { this.SetValue(TextProperty, value); }
    }
    private void ClickTweetButton(object sender, RoutedEventArgs e)
    {
    MessageBox.Show(this.Text, "Tweet!");
    }
    コード ビハインドに
    サックリ書ける

    View Slide

  42. User Control
    Window/Page と同じ作り方
    いわゆるポトペタが効く方法
    そのときしか使わないのが明らかな場合
    複雑なカスタマイズをサポートしない
     Template による外観変更ができない
     再利用可能とは言えない
    Pros
    Cons

    View Slide

  43. Custom Control
    Control 型から派生するコントロール
    WPF 標準コントロール群と同じ実装方法
    • TweetInputBox2.cs ロジック (コントロール機能の実装)
    必要な機能
    • テキスト入力 (文字列入力)
    • 残り文字数カウント (連動するカウンター)
    • ツイート送信ボタン (Click 相当イベント)

    View Slide

  44. Custom Control
    Control 型から派生するコントロール
    WPF 標準コントロール群と同じ実装方法
    • TweetInputBox2.cs
    • Themes/Generic.xaml
    両者は「名前付きパーツ」で連携する
    XAML は x:Name で名前付け、ロジックは GetTemplateChild() で取得
    ロジック (コントロール機能の実装)
    視覚構造と動作 (コントロール外観の実装)
    PART_Remaining PART_SendButton

    View Slide

  45. Control Contract
    名前付きパーツ
    コントロールの動作に必要な要素を宣言する
    例えば ComboBox の場合
    https://msdn.microsoft.com/ja-jp/library/ms752094.aspx
    TemplatePart 属性で
    名前と型を宣言する

    View Slide

  46. Control Contract
    機能 (ロジック) と外観の分離
    あくまで View 内で分離しただけ (MVVM とか関係ない)
    視覚構造と動作は ControlTemplate で定義するのが重要
    文字数オーバーしたら
    数字を赤くしたい…
    Label の Foreground を
    SolidColorBrush の Red に…

    View Slide

  47. Control Contract
    機能 (ロジック) と外観の分離
    あくまで View 内で分離しただけ (MVVM とか関係ない)
    視覚構造と動作は ControlTemplate で定義するのが重要
    文字数オーバーしたら
    数字を赤くしたい…
    Label の Foreground を
    SolidColorBrush の Red に…
    VisualStates
    • Valid
    • Invalid
    オーバーしたときどうなるか
    …は、ControlTemplate 側で
    自由に実装させるべき
    検証結果を
    VisualState で保持

    View Slide

  48. Control Authoring
    表現力・柔軟性を最大限利用しましょう
    Rich Content, Style, Trigger, Template, …
    外観ではなく機能に着目してコントロールを選択
    コントロール作成時は再利用要件に注目
    なし: User Control で楽々ポトペタ開発
    あり: Custom Control で機能と外観をうまく分離

    View Slide

  49. View Slide