Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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/

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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) ✕ ◯

Slide 7

Slide 7 text

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 のほうがいいよ! (弱気)

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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 %)

Slide 10

Slide 10 text

High DPI Improvements 例えば DPI 150 % 環境下において

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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 …?

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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; }

Slide 19

Slide 19 text

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 を使って ウィンドウの中身を拡縮 したりするとよいとおもう

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

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/

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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) ◯ ◯

Slide 28

Slide 28 text

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 のほうがいいよ! (強気)

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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!"); } コード ビハインドに サックリ書ける

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

No content