Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Road to UI Library

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

  • Be the first to comment

Road to UI Library

  1. 1. Road toUI Library 2014/11/29 Room metro #28Manato KAMEYA (@Grabacr07)
  2. 2. Subject •UI Library 作ってました −MetroRadiance(最近弄ってない…) −UserControl/ CustomControlの使いどころ共有 デモ& ライブコーディング中心 •UI Library によって −コントロール/ UI 資産の再利用性を高める −アプリのブランド化 あたりに興味を持って頂けると!
  3. 3. Agenda デスクトップアプリがこの先 生きのこるには Introduction CustomControl UserControl Conclusion Road to UI Library
  4. 4. •内容は個人に帰属します 所属する組織を代表するものではありません
  5. 5. Introduction
  6. 6. Self Introduction •Work −株式会社グラニ −Unity + C# でゲーム開発、まれにWPF •Private activity −Web: http://grabacr.net/ −Twitter: @Grabacr07(ぐらばく) −めとべや東京勉強会スタッフ −Microsoft MVP for Visual C#(2014/04 ~)
  7. 7. KanColleViewer •Windows Desktop app −.NET Framework 4.5 −Visual C# + WPF •艦これプレイングツール Internet Explorer Shell + FiddlerCore •2013/12 公開(約11 ヶ月) −1,650,000 downloads −Azure の料金がやゔぁい!
  8. 8. KanColleViewer •常にエゴサーチ(twitter) −メンタル鍛えられます •ユーザーの反応 −機能に対する反応・要望 −UI に対する反応・要望 •デベロッパーの反応 −「この見た目どうやって作んの」 UI ライブラリ自作しました
  9. 9. UI Libraries •最近のリッチなデスクトップアプリ
  10. 10. MetroRadiance •WPF カスタムコントロールライブラリ −カスタムコントロール&スタイル群 −別アプリでも同じ外観を再現できる ライブラリ(アセンブリ) を参照し、App.xamlのResourceDictionaryでマージするだけ −自分で作ってるアプリのブランド化 社内向けツールとかも <ResourceDictionary.MergedDictionaries> <ResourceDictionarySource="pack://application:,,,/MyControlLibrary;component/Styles/Controls.xaml" /> <ResourceDictionarySource="pack://application:,,,/MyControlLibrary;component/Styles/Icons.xaml" /> <ResourceDictionarySource="pack://application:,,,/MyControlLibrary;component/Themes/Dark.xaml" /> <ResourceDictionarySource="pack://application:,,,/MyControlLibrary;component/Themes/Accents/Purple.xaml" /> </ResourceDictionary.MergedDictionaries>
  11. 11. UI Libraries •最近のリッチなデスクトップアプリ JetBrains社のインストーラー •独自Style のコントロール群 •標準Chrome なし •Dark っぽいテーマ •進行状況不定バー(WinRTのアレ) <ProgressBarIsIndeterminate="True"> •ウィンドウの枠が光る •ウィンドウの枠が光る
  12. 12. Elysium •お手軽モダンUI ライブラリ これ使うだけでそれっぽく見える −http://elysium.codeplex.com/ −Zune 風コントロール・スタイル群 再現度はあまり高くない… −Visual Studio 2010 or 2012 が必要
  13. 13. Elysium •お手軽モダンUI ライブラリ これ使うだけでそれっぽく見える −http://elysium.codeplex.com/ −Zune 風コントロール・スタイル群 再現度はあまり高くない… −インストーラーに弾かれる VS2010 or 2012 が必要って言われる −独自のトースト通知システム Windows 7 でも通知できるが…
  14. 14. MahApps.Metro •お手軽モダンUI ライブラリ これ使うだけでそれっぽく見える −http://mahapps.com/MahApps.Metro/ −Windows ストアアプリ風 コントロール・スタイル群 −割とおすすめ
  15. 15. のちょっとした話? Template
  16. 16. Visual Structure (default Controls) •既存コントロールの構造を知るには −既定のテンプレートを生成
  17. 17. Another Controls ここにあるコントロールがすべて… なわけはない
  18. 18. Another Controls 右クリック> アイテムの選択 …で、表示するコントロールを選べる
  19. 19. Another Controls System.Windows.Controls.Primitives名前空間 RepeatButton, Popup, …
  20. 20. まずはオリジナルのコントロールの作成 User Control
  21. 21. Original Control •NumericUpDown −WPF にない鉄板コントロールということでひとつ −ボタンが押しにくく、 使い勝手悪くなりがち …を、今ここで実際に作ってみましょう(!) 要件 •ユーザーによるテキスト入力 •ボタン(値+1) •ボタン(値-1)
  22. 22. Case 1: User Control
  23. 23. Case 1: User Control •csproj> 追加> ユーザーコントロール •NumericUpDown.xaml
  24. 24. Case 1: User Control •csproj> 追加> ユーザーコントロール •NumericUpDown.xaml <DockPanel> <StackPanelDockPanel.Dock="Right"> <ButtonContent="▲" Click="CountUp" /> <ButtonContent="▼" Click="CountDown" /> </StackPanel> <TextBoxText="{BindingElementName=Root,Path=Value,Mode=TwoWay}" /> </DockPanel>
  25. 25. •csproj> 追加> ユーザーコントロール •NumericUpDown.xaml.cs(UserControlからの派生) publicintValue { get{return(int)GetValue(ValueProperty);} set{SetValue(ValueProperty,value);} } publicstaticreadonlyDependencyPropertyValueProperty= DependencyProperty.Register("Value",typeof(int),typeof(NumericUpDown),newPropertyMetadata(0)); privatevoidCountUp(objectsender,RoutedEventArgse) { this.Value++; } Case1: UserControl 依存関係プロパティ
  26. 26. Case 1: User Control •完成!… と、思うじゃろ? −そのときしか使わない場合は、それで完成。 −他のプロジェクトでも使い回したい場合は…? そして、他のプロジェクトでは外観を変更したい場合は…? 次のアプリでも使うよ ただしボタンをデカくしてくれ 大変申し訳ございません早急に 影響調査し対応致しますので今 暫くお待ち頂きますよう宜しk
  27. 27. Feature of User Control •UserControl型からの派生 −アプリケーション構築と同じ方法で作れる ▫Window / Page を作成するのと同じ要領で、ポトペタ開発 ▫既存のコンポーネントだけで構成されている −複雑なカスタマイズをサポートしない Background やBorderBrushを外部から指定する、程度の簡単なカスタマイズはでちる しかし、DataTemplateやControlTemplateによる外部からのカスタマイズはできない
  28. 28. 外観をカスタマイズできるコントロールの作成 Custom Control
  29. 29. Case 2: Custom Control
  30. 30. Case 2: Custom Control •csproj> 追加> 新しい項目> WPF> カスタムコントロール (Universal apps の場合は「テンプレートコントロール」) −NumericUpDown2.cs −Themes/Generic.xaml <StyleTargetType="{x:Typelocal:NumericUpDown2}"> <SetterProperty="Template"> <Setter.Value> <ControlTemplateTargetType="{x:Typelocal:NumericUpDown2}"> <BorderBackground="{TemplateBindingBackground}" BorderBrush="{TemplateBindingBorderBrush}" BorderThickness="{TemplateBindingBorderThickness}"> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> 操作ロジック(コントロールの機能の実装) 視覚的表現(コントロールの外観の実装) NumericUpDown2 は どうやって外観の定義まで 辿り着くか?
  31. 31. Feature of Custom Control •Control 型からの派生 −ロジックと外観の完全な分離 ▫コントロールの振る舞いを、ロジック(.cs) に ▫コントロールの外観を、Style/Template(Generic.xaml) に −.NET Framework が提供するコントロールと同じ実装 −コントロールの外観をカスタマイズ可能 ControlTemplateにより、あらゆる外観に設定可能
  32. 32. Parts and States Model •視覚的な構造と動作はControlTemplateで定義 −外観を直接ロジックで書くのはダメゼッタイ −NumericUpDownの場合 負の値のときは 文字を赤くしたい… TextBoxのForeground を SolidColorBrushのRed に…
  33. 33. Parts and States Model •視覚的な構造と動作はControlTemplateで定義 −外観を直接ロジックで書くのはダメゼッタイ −NumericUpDownの場合 負の値のときは 文字を赤くしたい… TextBoxのForeground を SolidColorBrushのRed に… ValueStates •Positive •Negative 正負をVisualStateで保持 負の値でどうなるか、は ControlTemplateで自由に実装
  34. 34. Parts and States Model •ControlTemplateとロジックの接点 −コントロールの要件(命題) を満たすうえで必要なパーツ −NumericUpDownの場合 ▫Click イベントを購読するため、ロジックから参照しなければならない Value を増減させるためのButton が必ず必要 名前付きパーツとOnApplyTemplateメソッド
  35. 35. Parts and States Model •名前付きパーツ −例えば、System.Windows.Controls.ComboBoxの場合 http://msdn.microsoft.com/ja-jp/library/ms752094.aspx
  36. 36. Parts and States Model •名前付きパーツ −例えば、System.Windows.Controls.ComboBoxの場合 http://msdn.microsoft.com/ja-jp/library/ms752094.aspx <Gridx:Name="templateRoot" SnapsToDevicePixels="true"> <!--中略--> <Popupx:Name="PART_Popup" AllowsTransparency="true" Grid.ColumnSpan="2" IsOpen="{BindingIsDropDownOpen,RelativeSource={RelativeSourceTemplatedParent}}" PopupAnimation="{DynamicResource{x:StaticSystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom"> <!--中略--> <Borderx:Name="border" Background="{StaticResourceTextBox.Static.Background}" Margin="{TemplateBindingBorderThickness}"> <TextBoxx:Name="PART_EditableTextBox" HorizontalContentAlignment="{TemplateBindingHorizontalContentAlignment}" IsReadOnly="{BindingIsReadOnly,RelativeSource={RelativeSourceTemplatedParent}}" Margin="{TemplateBindingPadding}" Style="{StaticResourceComboBoxEditableTextBox}" VerticalContentAlignment="{TemplateBindingVerticalContentAlignment}" /> </Border> </Grid> ComboBoxのControlTemplate(default)
  37. 37. Parts and States Model •OnApplyTemplateメソッド −ControlTemplateのVisual Tree が構築されたとき実行される ロジックからControlTemplateの実装にアクセスできる最も早いタイミング •GetTemplateChildメソッド −ControlTemplate内の名前付き要素を返す ControlTemplate内にある名前付きパーツのインスタンスを取得できる!
  38. 38. Parts and States Model •コントロールコントラクト −ロジックが使用する視覚的要素 名前付きパーツ −視覚的に作用するpublic PropertyNumericUpDownでいうValue プロパティなど −コントロールの状態とグループ VisualStates/ VisualStatesGroup
  39. 39. Parts and States Model •コントロールコントラクト −ロジックが使用する視覚的要素 名前付きパーツ −視覚的に作用するpublic PropertyNumericUpDownでいうValue プロパティなど −コントロールの状態とグループ VisualStates/ VisualStatesGroup [TemplatePart(Name = "PART_UpButton", Type = typeof(Button))] [TemplatePart(Name = "PART_DownButton", Type = typeof(Button))] publicclassCustomControl1: Control { privateButtonupButton; privateButtondownButton; publicoverridevoidOnApplyTemplate() { base.OnApplyTemplate(); this.upButton= this.GetTemplateChild("PART_UpButton") asButton; if(this.upButton!= null) { this.upButton.Click+= (sender, e) => this.Value++; } // 以下略
  40. 40. Custom Control •リソースを検索する順序 1.要素レベル 参照する要素からルート要素まで辿って検索 2.アプリケーションレベル Application (App.xaml) 内で定義されたリソース 3.テーマレベル Themes フォルダー内。つまりGeneric.xamlLuna.NormalColor.xamlとか使わんし…
  41. 41. Custom Control •リソースを検索する順序 1.要素レベル 参照する要素からルート要素まで辿って検索 2.アプリケーションレベル Application (App.xaml) 内で定義されたリソース 3.テーマレベル Themes フォルダー内。つまりGeneric.xamlLuna.NormalColor.xamlとか使わんし… <UserControl> <Grid> <StackPanel> <Border> <local:NumericUpDown/> </Border> </StackPanel> </Grid> </UserControl> NumericUpDown.Resources、 Border.Resources、StackPanel.Resources、 Grid.Resources、… の順に検索
  42. 42. Custom Control •リソースを検索する順序 1.要素レベル 参照する要素からルート要素まで辿って検索 2.アプリケーションレベル Application (App.xaml) 内で定義されたリソース 3.テーマレベル Themes フォルダー内。つまりGeneric.xamlLuna.NormalColor.xamlとか使わんし… <Applicaton> <Appliction.Resources> <!--ここにあるやつ--> </Appliction.Resources> </Applicaton> ※ただしアプリケーションのみ ライブラリ(.dll) はApplication を 持たないので
  43. 43. Custom Control •リソースを検索する順序 1.要素レベル 参照する要素からルート要素まで辿って検索 2.アプリケーションレベル Application (App.xaml) 内で定義されたリソース 3.テーマレベル Themes フォルダー内。つまりGeneric.xamlLuna.NormalColor.xamlとか使わんし…
  44. 44. DependentUpon-Generic.xaml •Generic.xaml、だいたい溢れる カスタムコントロールが増えてくると、保守たいへん −なので、Generic.<CustomControlName>.xamlに分離して DependentUponすると良さげ .csproj手動編集はつらすぎるので、拡張機能「VSCommands」とかとか
  45. 45. Without creating a new control •新しいコントロールを自作しないための方法 作らないで済むならそれに越したことはなく。 CircleButton、とか作りたくなってくるが… マウスオーバーと クリック時に 全体の色を変える… 円と矢印、 押しやすいように Margin 広めで… Dark テーマに 対応…
  46. 46. Without creating a new control •新しいコントロールを自作しないための方法 作らないで済むならそれに越したことはなく。 CircleButton、とか作りたくなってくるが… マウスオーバーと クリック時に 全体の色を変える… 円と矢印、 押しやすいように Margin 広めで… <Button> <Grid> <Ellipse/> <PathData=""/> </Grid> </Button> Button + リッチコンテンツ+ Style で実現可能 カスタムコントロールを作る必要は、ない Dark テーマに 対応…
  47. 47. Find the best possible choice •コントロールの価値命題 −こそが重要 −外観ではなく、コントロールの原理/ 振る舞い XAML Platform では、外観はいくらでも作り込めるので、一切関係ない TabControl ListBox ItemsControl 見た目は同じでも、要件が異なるので、それぞれ違うコントロールをベースにしている
  48. 48. Road to UI Library •作ったコントロールの再利用性を高めるために −UserControlはワンオフの実装、その時だけに使える −CustomControlは、WPF などと同じコントロールの実装 −再利用性を見込んで、の実装となると 断然カスタムコントロール(テンプレートコントロール)
  49. 49. Conclusion
  50. 50. Advent Calendar •XAML Advent Calendar 2014http://qiita.com/advent-calendar/2014/xaml •ご参加頂きたく。

×