スタイルの設定が可能なコントロールを設計するためのガイドラインGuidelines for Designing Stylable Controls

このドキュメントは、スタイルの設定とテンプレートの作成を簡単に行うためのコントロールを設計する際に考慮すべき一連のベスト プラクティスをまとめたものです。This document summarizes a set of best practices to consider when designing a control which you intend to be easily stylable and templatable. 組み込みの WPFWPF コントロール セットのテーマのコントロールのスタイルの操作で試行錯誤を繰り返した結果、この一連のベスト プラクティスにたどり着きました。We came to this set of best practices through a lot of trial and error while working on the theme control styles for the built-in WPFWPF control set. スタイリングの成功の鍵は、スタイルそのものであると同様に、適切に設計されたオブジェクト モデルの機能であることが分かりました。We learned that successful styling is as much a function of a well-designed object model as it is of the style itself. このドキュメントの対象読者は、スタイルの作成者ではなく、コントロールの作成者です。The intended audience for this document is the control author, not the style author.

用語Terminology

「スタイルとテンプレート」は、コントロールの作成者がコントロールの視覚的な側面をコントロールのスタイルとテンプレートに委ねることができるようにする一連のテクノロジを表します。"Styling and templating" refer to the suite of technologies that enable a control author to defer the visual aspects of the control to the style and template of the control. この一連のテクノロジは次のとおりです。This suite of technologies includes:

  • スタイル (プロパティ セッター、トリガー、およびストーリー ボードを含む)。Styles (including property setters, triggers, and storyboards).

  • リソースResources.

  • コントロール テンプレートControl templates.

  • データ テンプレートData templates.

スタイルとテンプレートの概要については、「スタイルとテンプレート」を参照してください。For an introduction to styling and templating, see Styling and Templating.

開始する前に: コントロールの理解Before You Start: Understanding Your Control

次のガイドラインに進む前に、コントロールの一般的な使用方法を理解し、これを定義する必要があります。Before you jump into these guidelines, it is important to understand and have defined the common usage of your control. スタイル設定は、規則に従わないことが多い可能性セットに遭遇します。Styling exposes an often unruly set of possibilities. (多くのアプリケーションで、多くの開発者によって) 広く使用されるように作成されるコントロールは、コントロールの視覚的な外観に広範な変更を加えるためにスタイル設定を使用できるという課題に直面しています。Controls that are written to be used broadly (in many applications, by many developers) face the challenge that styling can be used to make far-reaching changes to the visual appearance of the control. 実際には、スタイルのコントロールは、コントロールの作成者の意図に沿っていない場合すらあります。In fact, the styled control may not even resemble the control author's intentions. スタイル設定によって提供される柔軟性は実質的に無制限であるため、一般的な使用方法の概念を使用して、決定を詳しく調査できます。Since the flexibility offered by styling is essentially boundless, you can use the idea of common usage to help you scope your decisions.

コントロールの一般的な使用方法を理解するには、コントロールの価値提案について考慮することをお勧めします。To understand your control's common usage, it's good to think about the value proposition of the control. 作成したコントロールがテーブルにもたらすもので、その他のコントロールが提供できないものは何でしょうか。What does your control bring to the table that no other control can offer? 一般的な使用方法は、特定の視覚的な外観を意味するのではなく、コントロールの原理とその使用法の妥当な一連の想定を意味します。Common usage does not imply any specific visual appearance, but rather the philosophy of the control and a reasonable set of expectations about its usage. このことを理解すると、一般的な場合での、構成モデルとコントロールのスタイル定義の動作に関するある想定を行うことができます。This understanding allows you to make some assumptions about the composition model and the style-defined behaviors of the control in the common case. たとえば、ComboBoxの場合、一般的な使用法を理解しても、特定の ComboBox の角が丸くなっているかどうかについての洞察は得られませんが、ComboBox がポップアップウィンドウと、開いているかどうかを切り替えます。In the case of ComboBox, for example, understanding the common usage won't give you any insight about whether a particular ComboBox has rounded corners, but it will give you insight into the fact that the ComboBox probably needs a pop-up window and some way of toggling whether it is open.

一般的なガイドラインGeneral Guidelines

  • テンプレートのコントラクトは厳密に適用しないでください。Do not strictly enforce template contracts. コントロールのテンプレートのコントラクトは、要素、コマンド、バインディングまたはトリガーで構成されます。また、コントロールが正しく動作するために必要なまたは期待されているプロパティ設定が含まれる場合もあります。The template contract of a control might consist of elements, commands, bindings, triggers, or even property settings that are required or expected for a control to function properly.

    • コントラクトを可能な限り最小限に抑えます。Minimize contracts as much as possible.

    • 設計中 (つまり、設計ツールを使用時) にはコントロール テンプレートが未完成の状態であることが一般的です。Design around the expectation that during design time (that is, when using a design tool) it is common for a control template to be in an incomplete state. WPFWPF は「構成」状態のインフラストラクチャを提供しないため、コントロールは、このような状態が有効かもしれないという想定で構築する必要があります。does not offer a "composing" state infrastructure, so controls have to be built with the expectation that such a state might be valid.

    • テンプレートのコントラクトの側面に従わない場合、例外をスローしないでください。Do not throw exceptions when any aspect of a template contract is not followed. これらすべての点で、パネルの子が多すぎるまたは少なすぎる場合、例外をスローしないでください。Along these lines, panels should not throw exceptions if they have too many or too few children.

  • 周辺機能をテンプレートのヘルパー要素に組み込んでください。Factor peripheral functionality into template helper elements. 各コントロールは、コア機能と真の価値提案に重点を置き、コントロールの一般的な使用方法で定義されている必要があります。Each control should be focused on its core functionality and true value proposition and defined by the control's common usage. このために、テンプレート内で構成要素とヘルパー要素を使用し、周辺の動作およびビジュアル (つまり、コントロールのコア機能に関係のない動作とビジュアル) を有効にします。To that end, use composition and helper elements within the template to enable peripheral behaviors and visualizations, that is, those behaviors and visualizations that do not contribute to the core functionality of the control. ヘルパー要素は次の 3 つのカテゴリに分類されます。Helper elements fall into three categories:

    • Standalone ヘルパー型は、テンプレートで「匿名」で使用される、パブリックで再利用可能なコントロールまたはあるプリミティブです。つまり、ヘルパー要素もスタイル設定されたコントロールも他方を認識しません。Standalone helper types are public and reusable controls or primitives that are used "anonymously" in a template, meaning that neither the helper element nor the styled control is aware of the other. 技術的には、任意の要素を匿名型にできますが、このコンテキストではこの用語は、対象となるシナリオを有効にする専用機能をカプセル化するこれらの型について説明します。Technically, any element can be an anonymous type, but in this context the term describes those types that encapsulate specialized functionality to enable targeted scenarios.

    • Type-based ヘルパー要素は、専用機能をカプセル化する新しい型です。Type-based helper elements are new types that encapsulate specialized functionality. これらの要素は通常、一般的なコントロールまたはプリミティブより狭い範囲の機能を持つように設計されています。These elements are typically designed with a narrower range of functionality than common controls or primitives. Standalone ヘルパー要素とは異なり、Type-based ヘルパー要素は、これが使用されるコンテキストを認識し、通常これが属しているテンプレートを持つコントロールとデータを共有する必要があります。Unlike standalone helper elements, type-based helper elements are aware of the context in which they are used and typically must share data with the control to whose template they belong.

    • Named ヘルパー要素は、コントロールがテンプレート内で名前で検索することを想定している一般的なコントロールまたはプリミティブです。Named helper elements are common controls or primitives that a control expects to find within its template by name. これらの要素には、テンプレート内で既知の名前が与えられ、コントロールが要素を検索し、プログラムでやり取りできるようにします。These elements are given a well-known name within the template, making it possible for a control to find the element and interact with it programmatically. 特定の名前を持つ要素はテンプレート内に 1 つのみ存在できます。There can only be one element with a given name in any template.

    次の表は、現在コントロール スタイルで採用されているヘルパー要素を示しています (この一覧は完全ではありません)。The following table shows helper elements employed by control styles today (this list is not exhaustive):

    要素Element [種類]Type 使用者Used by
    ContentPresenter Type-basedType-based ButtonCheckBoxRadioButtonFrameなど (すべての ContentControl の種類)Button, CheckBox, RadioButton, Frame, and so on (all ContentControl types)
    ItemsPresenter Type-basedType-based ListBoxComboBoxMenuなど (すべての ItemsControl の種類)ListBox, ComboBox, Menu, and so on (all ItemsControl types)
    ToolBarOverflowPanel NamedNamed ToolBar
    Popup StandaloneStandalone ComboBoxToolBarMenuToolTipなどComboBox, ToolBar, Menu, ToolTip, and so on
    RepeatButton NamedNamed SliderScrollBarなどSlider, ScrollBar, and so on
    ScrollBar NamedNamed ScrollViewer
    ScrollViewer StandaloneStandalone ListBoxComboBoxMenuFrameなどListBox, ComboBox, Menu, Frame, and so on
    TabPanel StandaloneStandalone TabControl
    TextBox NamedNamed ComboBox
    TickBar Type-basedType-based Slider
  • ヘルパー要素の必要なユーザー指定のバインディングまたはプロパティ設定を最小限に抑えますMinimize required user-specified bindings or property settings on helper elements. コントロール テンプレート内で正しく機能するために、ヘルパー要素が特定のバインディングまたはプロパティ設定を要求することが一般的です。It is common for a helper element to require certain bindings or property settings in order to function properly within the control template. ヘルパー要素とテンプレート化されたコントロールがこれらの設定をできる限り多く確立する必要があります。The helper element and templated control should, as much as possible, establish these settings. プロパティの設定やバインディングの確立を行うとき、ユーザーが設定した値をオーバーライドしないように注意してください。When setting properties or establishing bindings, care should be taken to not override values set by the user. 具体的なベスト プラクティスは次のとおりです。Specific best practices are as follows:

    • Named ヘルパー要素は親によって識別する必要があり、親はこのヘルパー要素に必要な設定を確立する必要があります。Named helper elements should be identified by the parent and the parent should establish any required settings on the helper element.

    • Type-based ヘルパー要素は、自身に必要な設定を直接確立する必要があります。Type-based helper elements should establish any required settings directly on themselves. これを行うと、TemplatedParent (使用するテンプレートのコントロールの型) などの使用する情報コンテキストをクエリするヘルパー要素が必要になる場合があります。Doing this may require the helper element to query for information context in which it is being used, including its TemplatedParent (the control type of the template in which it is being used). たとえば、ContentPresenter は、ContentControl 派生型で使用されている場合、その TemplatedParentContent プロパティを Content プロパティに自動的にバインドします。For example, ContentPresenter automatically binds the Content property of its TemplatedParent to its Content property when used in a ContentControl derived type.

    • Standalone ヘルパー要素はこの方法では最適化できません。その理由は、定義上、ヘルパー要素もその親も他方を認識していないためです。Standalone helper elements cannot be optimized in this way because, by definition, neither the helper element nor the parent knows about the other.

  • Name プロパティを使用してテンプレート内で要素にフラグを設定しますUse the Name property to flag elements within a template. プログラムで要素にアクセスするためにそのスタイルで要素を検索する必要があるコントロールは、Name プロパティおよび FindName パラダイムを使用してこの操作を実行する必要があります。A control that needs to find an element in its style in order to access it programmatically should do so using the Name property and the FindName paradigm. コントロールは、要素が見つからない場合には例外をスローせず、その要素を必要としていた機能を安全に無効にします。A control should not throw an exception when an element is not found, but silently and gracefully disable the functionality which required that element.

  • コントロールの状態と動作をスタイルで表現するためのベスト プラクティスを使用します。Use best practices for expressing control state and behavior in a style. コントロールの状態の変更と動作をスタイルで表すためのベスト プラクティスの順序付きリストを次に示します。The following is an ordered list of best practices for expressing control state changes and behavior in a style. シナリオを有効にするリストの最初の項目を使用する必要があります。You should use the first item on the list that enables your scenario.

    1. プロパティ バインディングProperty binding. 例: ComboBox.IsDropDownOpenToggleButton.IsChecked間のバインド。Example: binding between ComboBox.IsDropDownOpen and ToggleButton.IsChecked.

    2. トリガーされたプロパティの変更またはプロパティのアニメーション。Triggered property changes or property animations. 例: Buttonのホバー状態。Example: the hover state of a Button.

    3. コマンド。Command. 例: ScrollBarで / LineDownCommandLineUpCommandします。Example: LineUpCommand / LineDownCommand in ScrollBar.

    4. Standalone ヘルパー要素。Standalone helper elements. 例: TabControlでの TabPanelExample: TabPanel in TabControl.

    5. Type-based ヘルパー型。Type-based helper types. 例: ButtonContentPresenterSliderTickBar ます。Example: ContentPresenter in Button, TickBar in Slider.

    6. Named ヘルパー要素。Named helper elements. 例: ComboBoxでの TextBoxExample: TextBox in ComboBox.

    7. Named ヘルパー型からのバブル イベント。Bubbled events from named helper types. スタイル要素からバブル イベントをリッスンする場合、イベントを生成する要素を一意に識別できる必要があります。If you listen for bubbled events from a style element, you should require that the element generating the event can be uniquely identified. 例: ToolBarでの ThumbExample: Thumb in ToolBar.

    8. カスタム OnRender 動作。Custom OnRender behavior. 例: Buttonでの ButtonChromeExample: ButtonChrome in Button.

  • (テンプレートのトリガー) ではなくスタイルのトリガーを控えめに使用しますUse style triggers (as opposed to template triggers) sparingly. テンプレートの要素のプロパティに影響するトリガーは、テンプレートで宣言する必要があります。Triggers that affect properties on elements in the template must be declared in the template. コントロールのプロパティに影響するトリガー (TargetName 以外) は、テンプレートの変更がトリガーも破棄することがわかっていない限り、スタイルで宣言できます。Triggers that affect properties on the control (no TargetName) may be declared in the style unless you know that changing the template should also destroy the trigger.

  • 既存のスタイル パターンとの一貫性を保ちます。Be consistent with existing styling patterns. 多くの場合、問題を解決する方法は複数あります。Many times there are multiple ways to solve a problem. 可能な場合、既存のコントロール スタイル設定パターンとの一貫性を維持してください。Be aware of and, when possible, consistent with existing control styling patterns. これは、同じ基本データ型 (たとえば、ContentControlItemsControlRangeBaseなど) から派生したコントロールでは特に重要です。This is especially important for controls that derive from the same base type (for example, ContentControl, ItemsControl, RangeBase, and so on).

  • プロパティを公開し、テンプレートを再設定せずに一般的なカスタマイズ シナリオを有効にしますExpose properties to enable common customization scenarios without retemplating. WPFWPF はプラグ可能/カスタマイズ可能な部分をサポートしないため、コントロールのユーザーは 2 つのカスタマイズ メソッドのみを使用できます。プロパティを直接設定するか、スタイルを使用してプロパティを設定するかです。does not support pluggable/customizable parts, so a control user is left with only two methods of customization: setting properties directly or setting properties using styles. このことを念頭に置いて、このメソッドを使用しない場合にはテンプレートの再設定をしなければならなくなる、非常に一般的で優先度の高いカスタマイズのシナリオを対象とした、数に限りのあるプロパティに使用することが適切です。With that in mind, it is appropriate to surface a limited number of properties targeted at very common, high-priority customization scenarios which would otherwise require the retemplating. カスタマイズのシナリオをいつ有効にし、どのように有効にするかについてのベスト プラクティスを次に示します。Here are best practices for when and how to enable customization scenarios:

    • 非常に一般的なカスタマイズをコントロールのプロパティとして公開し、テンプレートで使用する必要があります。Very common customizations should be exposed as properties on the control and consumed by the template.

    • (まれではないが) あまり一般的ではないカスタマイズは、添付プロパティとして公開し、テンプレートで使用する必要があります。Less common (though not rare) customizations should be exposed as attached properties and consumed by the template.

    • 既知だがまれなカスタマイズでテンプレートの再設定が必要になることは容認されます。It is acceptable for known but rare customizations to require retemplating.

テーマの注意事項Theme Considerations

  • テーマ スタイルは、すべてのテーマで一貫性のあるプロパティのセマンティクスを持つようにする必要がありますが、その保証はありませんTheme styles should attempt to have consistent property semantics across all themes, but make no guarantee. ドキュメントの一部として、コントロールは、コントロールのプロパティのセマンティクス、つまり、コントロールのプロパティの「意味」を説明するドキュメントが必要です。As part of its documentation, your control should have a document describing the control's property semantics, that is, the "meaning" of a property for a control. たとえば、ComboBox コントロールは ComboBox内の Background プロパティの意味を定義する必要があります。For example, the ComboBox control should define the meaning of the Background property within ComboBox. コントロールの既定のスタイルは、すべてのテーマでそのドキュメントで定義されたセマンティクスに従おうとする必要があります。The default styles for your control should attempt to follow the semantics defined in that document across all themes. 一方コントロールのユーザーは、プロパティのセマンティクスがテーマごとに変わる可能性があることを認識する必要があります。Control users, on the other hand, should be aware that property semantics can change from theme to theme. 特定のケースでは、指定したプロパティが特定のテーマで必要な視覚上の制約下では表現できない場合があります。In certain cases, a given property may not be expressible under the visual constraints required by a particular theme. (たとえば、クラシックのテーマには、多くのコントロールに対して Thickness の適用先にできる単一の境界線がありません。)(The Classic theme, for example, does not have a single border to which Thickness can be applied for many controls.)

  • テーマ スタイルは、すべてのテーマで一貫性のあるトリガー セマンティクスを持つ必要はありませんTheme styles do not need to have consistent trigger semantics across all themes. トリガーまたはアニメーションを通してコントロール スタイルによって公開されている動作は、テーマごとに異なります。The behavior exposed by a control style through triggers or animations may vary from theme to theme. コントロールのユーザーは、すべてのテーマで特定の動作を実現するために、コントロールが同じメカニズムを必ずしも使用しないことを認識している必要があります。Control users should be aware that a control will not necessarily employ the same mechanism to achieve a particular behavior across all themes. たとえば、1 つのテーマがアニメーションを使用してホバー動作を表現し、別のテーマがトリガーを使用する場合があります。One theme, for example, may use an animation to express hover behavior where another theme uses a trigger. これにより、カスタマイズされたコントロールでの動作の保持に不整合が生じる可能性があります。This can result in inconsistencies in behavior preservation on customized controls. (たとえば、背景のプロパティの変更は、ホバー状態がトリガーを使用して表現されている場合、コントロールのホバー状態には影響しません。(Changing the background property, for example, might not affect the hover state of the control if that state is expressed using a trigger. ただし、ホバー状態がアニメーションを使用して実装されている場合、背景の変更がアニメーションを損なって修復できなくなり、状態遷移が発生する可能性があります。)However, if the hover state is implemented using an animation, changing to background could irreparably break the animation and therefore the state transition.)

  • テーマ スタイルは、すべてのテーマで一貫性のある「レイアウト」セマンティクスを持つ必要はありませんTheme styles do not need to have consistent "layout" semantics across all themes. たとえば、既定のスタイルは、コントロールがすべてのテーマで同じ量のサイズを占有することを保証する必要はなく、また、コントロールがすべてのテーマで同じコンテンツの余白/パディングを持つことを保証する必要もありません。For example, the default style does not need to guarantee that a control will occupy the same amount of size in all themes or guarantee that a control will have the same content margins / padding across all themes.

関連項目See also