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

Road to UI Library

Grabacr07
December 01, 2014

Road to UI Library

Room metro #28 XAML Day で使用した資料です。
コントロール自作、そしてライブラリ化するための方法や注意点など。

Grabacr07

December 01, 2014
Tweet

More Decks by Grabacr07

Other Decks in Technology

Transcript

  1. Road to
    UI Library
    2014/11/29 Room metro #28
    Manato KAMEYA (@Grabacr07)

    View Slide

  2. Subject
    • UI Library 作ってました
    − MetroRadiance (最近弄ってない…)
    − UserControl / CustomControl の使いどころ共有
    デモ & ライブコーディング中心
    • UI Library によって
    − コントロール / UI 資産の再利用性を高める
    − アプリのブランド化
    あたりに興味を持って頂けると!

    View Slide

  3. Agenda
    デスクトップ アプリがこの先
    生きのこるには
    Introduction
    CustomControl
    UserControl
    Conclusion
    Road to UI Library

    View Slide

  4. • 内容は個人に帰属します
    所属する組織を代表するものではありません

    View Slide

  5. Introduction

    View Slide

  6. Self Introduction
    • Work
    − 株式会社グラニ
    − Unity + C# でゲーム開発、まれに WPF
    • Private activity
    − Web: http://grabacr.net/
    − Twitter: @Grabacr07 (ぐらばく)
    − めとべや東京勉強会スタッフ
    − Microsoft MVP for Visual C# (2014/04 ~)

    View Slide

  7. KanColleViewer
    • Windows Desktop app
    − .NET Framework 4.5
    − Visual C# + WPF
    • 艦これ プレイングツール
    Internet Explorer Shell + FiddlerCore
    • 2013/12 公開 (約 11 ヶ月)
    − 1,650,000 downloads
    − Azure の料金がやゔぁい!

    View Slide

  8. KanColleViewer
    • 常にエゴサーチ (twitter)
    − メンタル鍛えられます
    • ユーザーの反応
    − 機能に対する反応・要望
    − UI に対する反応・要望
    • デベロッパーの反応
    − 「この見た目どうやって作んの」
    UI ライブラリ自作しました

    View Slide

  9. UI Libraries
    • 最近のリッチなデスクトップ アプリ

    View Slide

  10. MetroRadiance
    • WPF カスタム コントロール ライブラリ
    − カスタム コントロール&スタイル群
    − 別アプリでも同じ外観を再現できる
    ライブラリ (アセンブリ) を参照し、App.xaml の ResourceDictionary でマージするだけ
    − 自分で作ってるアプリのブランド化
    社内向けツールとかも






    View Slide

  11. UI Libraries
    • 最近のリッチなデスクトップ アプリ
    JetBrains 社のインストーラー
    • 独自 Style のコントロール群
    • 標準 Chrome なし
    • Dark っぽいテーマ
    • 進行状況不定バー (WinRT のアレ)

    • ウィンドウの枠が光る
    • ウィンドウの枠が光る

    View Slide

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

    View Slide

  13. Elysium
    • お手軽モダン UI ライブラリ
    これ使うだけでそれっぽく見える
    − http://elysium.codeplex.com/
    − Zune 風コントロール・スタイル群
    再現度はあまり高くない…
    − インストーラーに弾かれる
    VS2010 or 2012 が必要って言われる
    − 独自のトースト通知システム
    Windows 7 でも通知できるが…

    View Slide

  14. MahApps.Metro
    • お手軽モダン UI ライブラリ
    これ使うだけでそれっぽく見える
    − http://mahapps.com/MahApps.Metro/
    − Windows ストアアプリ風
    コントロール・スタイル群
    − 割とおすすめ

    View Slide

  15. のちょっとした話?
    Template

    View Slide

  16. Visual Structure (default Controls)
    • 既存コントロールの構造を知るには
    − 既定のテンプレートを生成

    View Slide

  17. Another Controls
    ここにあるコントロールがすべて…
    なわけはない

    View Slide

  18. Another Controls
    右クリック > アイテムの選択
    …で、表示するコントロールを選べる

    View Slide

  19. Another Controls
    System.Windows.Controls.Primitives 名前空間
    RepeatButton, Popup, …

    View Slide

  20. まずはオリジナルのコントロールの作成
    User Control

    View Slide

  21. Original Control
    • NumericUpDown
    − WPF にない鉄板コントロールということでひとつ
    − ボタンが押しにくく、
    使い勝手悪くなりがち
    … を、今ここで実際に作ってみましょう (!)
    要件
    • ユーザーによるテキスト入力
    • ボタン (値 +1)
    • ボタン (値 - 1)

    View Slide

  22. Case 1: User Control

    View Slide

  23. Case 1: User Control
    • csproj > 追加 > ユーザー コントロール
    • NumericUpDown.xaml

    View Slide

  24. Case 1: User Control
    • csproj > 追加 > ユーザー コントロール
    • NumericUpDown.xaml


    Click="CountUp" />
    Click="CountDown" />



    View Slide

  25. • csproj > 追加 > ユーザー コントロール
    • NumericUpDown.xaml.cs (UserControl からの派生)
    public int Value
    {
    get { return (int)GetValue(ValueProperty); }
    set { SetValue(ValueProperty, value); }
    }
    public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register("Value", typeof(int), typeof(NumericUpDown), new PropertyMetadata(0));
    private void CountUp(object sender, RoutedEventArgs e)
    {
    this.Value++;
    }
    Case 1: User Control
    依存関係プロパティ

    View Slide

  26. Case 1: User Control
    • 完成! … と、思うじゃろ?
    − そのときしか使わない場合は、それで完成。
    − 他のプロジェクトでも使い回したい場合は…?
    そして、他のプロジェクトでは外観を変更したい場合は…?
    次のアプリでも使うよ
    ただしボタンをデカくしてくれ
    大変申し訳ございません早急に
    影響調査し対応致しますので今
    暫くお待ち頂きますよう宜しk

    View Slide

  27. Feature of User Control
    • UserControl 型からの派生
    − アプリケーション構築と同じ方法で作れる
    ▫ Window / Page を作成するのと同じ要領で、ポトペタ開発
    ▫ 既存のコンポーネントだけで構成されている
    − 複雑なカスタマイズをサポートしない
    Background や BorderBrush を外部から指定する、程度の簡単なカスタマイズはでちる
    しかし、DataTemplate や ControlTemplate による外部からのカスタマイズはできない

    View Slide

  28. 外観をカスタマイズできるコントロールの作成
    Custom Control

    View Slide

  29. Case 2: Custom Control

    View Slide

  30. Case 2: Custom Control
    • csproj > 追加 > 新しい項目 > WPF > カスタム コントロール
    (Universal apps の場合は「テンプレート コントロール」)
    − NumericUpDown2.cs
    − Themes/Generic.xaml
    <br/><Setter Property="Template"><br/><Setter.Value><br/><ControlTemplate TargetType="{x:Type local:NumericUpDown2}"><br/><Border Background="{TemplateBinding Background}"<br/>BorderBrush="{TemplateBinding BorderBrush}"<br/>BorderThickness="{TemplateBinding BorderThickness}"><br/></Border><br/></ControlTemplate><br/></Setter.Value><br/></Setter><br/>
    操作ロジック (コントロールの機能の実装)
    視覚的表現 (コントロールの外観の実装)
    NumericUpDown2 は
    どうやって外観の定義まで
    辿り着くか?

    View Slide

  31. Feature of Custom Control
    • Control 型からの派生
    − ロジックと外観の完全な分離
    ▫ コントロールの振る舞いを、ロジック (.cs) に
    ▫ コントロールの外観を、Style/Template (Generic.xaml) に
    − .NET Framework が提供するコントロールと同じ実装
    − コントロールの外観をカスタマイズ可能
    ControlTemplate により、あらゆる外観に設定可能

    View Slide

  32. Parts and States Model
    • 視覚的な構造と動作は ControlTemplate で定義
    − 外観を直接ロジックで書くのはダメゼッタイ
    − NumericUpDown の場合
    負の値のときは
    文字を赤くしたい…
    TextBox の Foreground を
    SolidColorBrush の Red に…

    View Slide

  33. Parts and States Model
    • 視覚的な構造と動作は ControlTemplate で定義
    − 外観を直接ロジックで書くのはダメゼッタイ
    − NumericUpDown の場合
    負の値のときは
    文字を赤くしたい…
    TextBox の Foreground を
    SolidColorBrush の Red に…
    ValueStates
    • Positive
    • Negative
    正負を VisualState で保持
    負の値でどうなるか、は
    ControlTemplate で自由に実装

    View Slide

  34. Parts and States Model
    • ControlTemplate とロジックの接点
    − コントロールの要件 (命題) を満たすうえで必要なパーツ
    − NumericUpDown の場合
    ▫ Click イベントを購読するため、ロジックから参照しなければならない
    Value を増減させるための Button が必ず必要
    名前付きパーツと OnApplyTemplate メソッド

    View Slide

  35. Parts and States Model
    • 名前付きパーツ
    − 例えば、System.Windows.Controls.ComboBox の場合
    http://msdn.microsoft.com/ja-jp/library/ms752094.aspx

    View Slide

  36. Parts and States Model
    • 名前付きパーツ
    − 例えば、System.Windows.Controls.ComboBox の場合
    http://msdn.microsoft.com/ja-jp/library/ms752094.aspx
    SnapsToDevicePixels="true">

    AllowsTransparency="true"
    Grid.ColumnSpan="2"
    IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"
    PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}"
    Placement="Bottom">

    Background="{StaticResource TextBox.Static.Background}"
    Margin="{TemplateBinding BorderThickness}">
    HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
    IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource TemplatedParent}}"
    Margin="{TemplateBinding Padding}"
    Style="{StaticResource ComboBoxEditableTextBox}"
    VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />


    ComboBox の ControlTemplate (default)

    View Slide

  37. Parts and States Model
    • OnApplyTemplate メソッド
    − ControlTemplate の Visual Tree が構築されたとき実行される
    ロジックから ControlTemplate の実装にアクセスできる最も早いタイミング
    • GetTemplateChild メソッド
    − ControlTemplate 内の名前付き要素を返す
    ControlTemplate 内にある名前付きパーツのインスタンスを取得できる!

    View Slide

  38. Parts and States Model
    • コントロール コントラクト
    − ロジックが使用する視覚的要素
    名前付きパーツ
    − 視覚的に作用する public Property
    NumericUpDown でいう Value プロパティなど
    − コントロールの状態とグループ
    VisualStates / VisualStatesGroup

    View Slide

  39. Parts and States Model
    • コントロール コントラクト
    − ロジックが使用する視覚的要素
    名前付きパーツ
    − 視覚的に作用する public Property
    NumericUpDown でいう Value プロパティなど
    − コントロールの状態とグループ
    VisualStates / VisualStatesGroup
    [TemplatePart(Name = "PART_UpButton", Type = typeof(Button))]
    [TemplatePart(Name = "PART_DownButton", Type = typeof(Button))]
    public class CustomControl1 : Control
    {
    private Button upButton;
    private Button downButton;
    public override void OnApplyTemplate()
    {
    base.OnApplyTemplate();
    this.upButton = this.GetTemplateChild("PART_UpButton") as Button;
    if (this.upButton != null)
    {
    this.upButton.Click += (sender, e) => this.Value++;
    }
    // 以下略

    View Slide

  40. Custom Control
    • リソースを検索する順序
    1. 要素レベル
    参照する要素からルート要素まで辿って検索
    2. アプリケーション レベル
    Application (App.xaml) 内で定義されたリソース
    3. テーマ レベル
    Themes フォルダー内。つまり Generic.xaml
    Luna.NormalColor.xaml とか使わんし…

    View Slide

  41. Custom Control
    • リソースを検索する順序
    1. 要素レベル
    参照する要素からルート要素まで辿って検索
    2. アプリケーション レベル
    Application (App.xaml) 内で定義されたリソース
    3. テーマ レベル
    Themes フォルダー内。つまり Generic.xaml
    Luna.NormalColor.xaml とか使わんし…









    NumericUpDown.Resources、
    Border.Resources、StackPanel.Resources、
    Grid.Resources、… の順に検索

    View Slide

  42. Custom Control
    • リソースを検索する順序
    1. 要素レベル
    参照する要素からルート要素まで辿って検索
    2. アプリケーション レベル
    Application (App.xaml) 内で定義されたリソース
    3. テーマ レベル
    Themes フォルダー内。つまり Generic.xaml
    Luna.NormalColor.xaml とか使わんし…





    ※ ただしアプリケーションのみ
    ライブラリ (.dll) は Application を
    持たないので

    View Slide

  43. Custom Control
    • リソースを検索する順序
    1. 要素レベル
    参照する要素からルート要素まで辿って検索
    2. アプリケーション レベル
    Application (App.xaml) 内で定義されたリソース
    3. テーマ レベル
    Themes フォルダー内。つまり Generic.xaml
    Luna.NormalColor.xaml とか使わんし…

    View Slide

  44. DependentUpon - Generic.xaml
    • Generic.xaml、だいたい溢れる
    カスタム コントロールが増えてくると、保守たいへん
    − なので、Generic..xaml に分離して
    DependentUpon すると良さげ
    .csproj 手動編集はつらすぎるので、拡張機能「VSCommands」とかとか

    View Slide

  45. Without creating a new control
    • 新しいコントロールを自作しないための方法
    作らないで済むならそれに越したことはなく。
    CircleButton、とか作りたくなってくるが…
    マウス オーバーと
    クリック時に
    全体の色を変える…
    円と矢印、
    押しやすいように
    Margin 広めで…
    Dark テーマに
    対応…

    View Slide

  46. Without creating a new control
    • 新しいコントロールを自作しないための方法
    作らないで済むならそれに越したことはなく。
    CircleButton、とか作りたくなってくるが…
    マウス オーバーと
    クリック時に
    全体の色を変える…
    円と矢印、
    押しやすいように
    Margin 広めで…






    Button + リッチ コンテンツ + Style で実現可能
    カスタム コントロールを作る必要は、ない
    Dark テーマに
    対応…

    View Slide

  47. Find the best possible choice
    • コントロールの価値命題
    − こそが重要
    − 外観ではなく、コントロールの原理 / 振る舞い
    XAML Platform では、外観はいくらでも作り込めるので、一切関係ない
    TabControl
    ListBox
    ItemsControl
    見た目は同じでも、要件が異なるので、それぞれ違うコントロールをベースにしている

    View Slide

  48. Road to UI Library
    • 作ったコントロールの再利用性を高めるために
    − UserControl はワンオフの実装、その時だけに使える
    − CustomControl は、WPF などと同じコントロールの実装
    − 再利用性を見込んで、の実装となると
    断然カスタム コントロール (テンプレート コントロール)

    View Slide

  49. Conclusion

    View Slide

  50. Advent Calendar
    • XAML Advent Calendar 2014
    http://qiita.com/advent-calendar/2014/xaml
    • ご参加頂きたく。

    View Slide