コントロールの作成の概要Control authoring overview

Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) コントロール モデルの機能拡張により、新しいコントロールを作成する必要性が大幅に削減されます。The extensibility of the Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) control model greatly reduces the need to create a new control. ただし、場合によっては、カスタム コントロールを作成する必要があります。However, in certain cases you may still need to create a custom control. このトピックでは、カスタム コントロールを作成する必要性を最小限に抑える機能と、Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) のさまざまなコントロール作成モデルについて説明します。This topic discusses the features that minimize your need to create a custom control and the different control authoring models in Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF). また、新しいコントロールを作成する方法も示します。This topic also demonstrates how to create a new control.

新しいコントロールの作成に代わる方法Alternatives to Writing a New Control

従来は、既存のコントロールをカスタマイズする場合、背景色、境界線の幅、フォントのサイズなど、コントロールの標準プロパティを変更するなどの範囲に制限されていました。Historically, if you wanted to get a customized experience from an existing control, you were limited to changing the standard properties of the control, such as background color, border width, and font size. これらの定義済みのパラメーター以外に、コントロールの外観や動作にまでカスタマイズを拡張しようとすると、通常、既存のコントロールを継承し、コントロールを描画するメソッドをオーバーライドして、新しいコントロールを作成する必要がありました。If you wished to extend the appearance or behavior of a control beyond these predefined parameters, you would need to create a new control, usually by inheriting from an existing control and overriding the method responsible for drawing the control. その方法は今でも選択できますが、WPFWPF の場合、リッチ コンテンツ モデル、スタイル、テンプレート、トリガーを使用して、既存のコントロールをカスタマイズできます。Although that is still an option, WPFWPF enables to you customize existing controls by using its rich content model, styles, templates, and triggers. 新しいコントロールを作成しなくても、これらの機能を使用して、カスタマイズされた一貫性のあるエクスペリエンスを得られる方法としては、次のような例が挙げられます。The following list gives examples of how these features can be used to create custom and consistent experiences without having to create a new control.

  • リッチ コンテンツ。Rich Content. 標準の WPFWPF コントロールの多くがリッチ コンテンツをサポートしています。Many of the standard WPFWPF controls support rich content. たとえば、Button のコンテンツ プロパティは Object 型であるため、理論的にはどのようなものでも Button 上に表示できます。For example, the content property of a Button is of type Object, so theoretically anything can be displayed on a Button. ボタンに画像とテキストを表示するには、画像と TextBlockStackPanel に追加し、その StackPanelContent プロパティに割り当てます。To have a button display an image and text, you can add an image and a TextBlock to a StackPanel and assign the StackPanel to the Content property. コントロールには、WPFWPF の視覚的要素と任意のデータを表示できるため、複雑な視覚化をサポートするために、新しいコントロールを作成したり、既存のコントロールを変更したりする必要性が少なくなります。Because the controls can display WPFWPF visual elements and arbitrary data, there is less need to create a new control or to modify an existing control to support a complex visualization. Button のコンテンツ モデルや WPFWPF のその他のコンテンツ モデルの詳細については、「WPF のコンテンツ モデル」を参照してください。For more information about the content model for Button and other content models in WPFWPF, see WPF Content Model.

  • スタイルStyles. Style は、コントロールのプロパティを表す値のコレクションです。A Style is a collection of values that represent properties for a control. スタイルを使用すると、新しいコントロールを作成しなくても、必要なコントロールの外観と動作を備えた再利用可能な表現を作成できます。By using styles, you can create a reusable representation of a desired control appearance and behavior without writing a new control. たとえば、すべての TextBlock コントロールにフォント サイズ 14 の赤色の Arial フォントを設定するとします。For example, assume that you want all of your TextBlock controls to have red, Arial font with a font size of 14. そこで、リソースとしてスタイルを作成し、それに応じて、適切なプロパティを設定します。You can create a style as a resource and set the appropriate properties accordingly. すると、アプリケーションに追加する TextBlock はすべて同じ外観になります。Then every TextBlock that you add to your application will have the same appearance.

  • データ テンプレート。Data Templates. DataTemplate を使用すると、コントロールにデータを表示する方法をカスタマイズできます。A DataTemplate enables you to customize how data is displayed on a control. たとえば、DataTemplate を使用して、ListBox にデータを表示する方法を指定できます。For example, a DataTemplate can be used to specify how data is displayed in a ListBox. この例については、「データ テンプレートの概要」を参照してください。For an example of this, see Data Templating Overview. DataTemplate については、データの表示方法のカスタマイズのほか、UI 要素を含めることもでき、カスタム UI の柔軟性を高めることができます。In addition to customizing the appearance of data, a DataTemplate can include UI elements, which gives you a lot of flexibility in custom UIs. たとえば、DataTemplate を使用して、ComboBox を作成し、その各項目にチェック ボックスを付けることができます。For example, by using a DataTemplate, you can create a ComboBox in which each item contains a check box.

  • コントロール テンプレート。Control Templates. WPFWPF のコントロールの多くでは、ControlTemplate を使用して、コントロールの構造と外観が定義されています。これにより、コントロールの外観と機能を分離できます。Many controls in WPFWPF use a ControlTemplate to define the control's structure and appearance, which separates the appearance of a control from the functionality of the control. コントロールの ControlTemplate を再定義すると、その外観を大幅に変更できます。You can drastically change the appearance of a control by redefining its ControlTemplate. たとえば、信号機のような外観のコントロールが必要だとします。For example, suppose you want a control that looks like a stoplight. このコントロールのユーザー インターフェイスと機能は単純です。This control has a simple user interface and functionality. コントロールは 3 つの円で構成され、一度に点灯するのはそのうちの 1 つだけです。The control is three circles, only one of which can be lit up at a time. 少し考えた結果、RadioButton を使用すると、一度に 1 つだけ選択する機能を実現できることに気付いたとします。しかし、RadioButton の既定の外観は信号機のライトとは全然似ていません。After some reflection, you might realize that a RadioButton offers the functionality of only one being selected at a time, but the default appearance of the RadioButton looks nothing like the lights on a stoplight. RadioButton では、コントロール テンプレートを使用して外観を定義しているため、コントロールの要件に合わせて ControlTemplate を再定義し、オプション ボタンで信号機を実現するのは簡単です。Because the RadioButton uses a control template to define its appearance, it is easy to redefine the ControlTemplate to fit the requirements of the control, and use radio buttons to make your stoplight.


    RadioButton では DataTemplate を使用できますが、この例の場合、DataTemplate では不十分です。Although a RadioButton can use a DataTemplate, a DataTemplate is not sufficient in this example. DataTemplate では、コントロールのコンテンツの外観が定義されます。The DataTemplate defines the appearance of the content of a control. RadioButton の場合、コンテンツとは、RadioButton が選択されているかどうかを示す円の右側に表示される内容です。In the case of a RadioButton, the content is whatever appears to the right of the circle that indicates whether the RadioButton is selected. 信号機の例では、オプション ボタンに必要なのは "点灯" する円だけです。In the example of the stoplight, the radio button needs just be a circle that can "light up." 信号機の外観の要件が RadioButton の既定の外観とは大きく異なるため、ControlTemplate を再定義する必要があります。Because the appearance requirement for the stoplight is so different than the default appearance of the RadioButton, it is necessary to redefine the ControlTemplate. 一般的に、コントロールのコンテンツ (またはデータ) を定義するために DataTemplate を使用し、コントロールの構成方法を定義するために ControlTemplate を使用します。In general a DataTemplate is used for defining the content (or data) of a control, and a ControlTemplate is used for defining how a control is structured.

  • トリガー。Triggers. Trigger を使用すると、新しいコントロールを作成しなくても、コントロールの外観と動作を動的に変更できます。A Trigger allows you to dynamically change the appearance and behavior of a control without creating a new control. たとえば、複数の ListBox コントロールを使用するアプリケーションがあり、各 ListBox の選択項目を赤色の太字で表示するとします。For example, suppose you have multiple ListBox controls in your application and want the items in each ListBox to be bold and red when they are selected. まず思いつくのは、ListBox を継承したクラスを作成して、OnSelectionChanged メソッドをオーバーライドし、選択項目の外観を変更する方法ですが、ListBoxItem のスタイルに選択項目の外観を変更するトリガーを追加する方法の方が適切です。Your first instinct might be to create a class that inherits from ListBox and override the OnSelectionChanged method to change the appearance of the selected item, but a better approach is to add a trigger to a style of a ListBoxItem that changes the appearance of the selected item. トリガーを使用すると、プロパティ値を変更したり、プロパティ値に基づいた処理を実行したりできます。A trigger enables you to change property values or take actions based on the value of a property. EventTrigger を使用すると、イベント発生時に処理を実行できます。An EventTrigger enables you to take actions when an event occurs.

スタイル、テンプレート、トリガーの詳細については、「スタイルとテンプレート」を参照してください。For more information about styles, templates, and triggers, see Styling and Templating.

一般に、既存のコントロールと同じ機能を持ち、外観が異なるコントロールが必要な場合は、このセクションで説明した方法のいずれかを使用して、既存のコントロールの外観を変更できないかどうかをまず検討することをお勧めします。In general, if your control mirrors the functionality of an existing control, but you want the control to look different, you should first consider whether you can use any of the methods discussed in this section to change the existing control's appearance.

コントロール作成モデルModels for Control Authoring

リッチ コンテンツ モデル、スタイル、テンプレート、トリガーを使用すると、新しいコントロールを作成する必要性が最小限に抑えられます。The rich content model, styles, templates, and triggers minimize the need for you to create a new control. ただし、新しいコントロールを作成する必要がある場合は、WPFWPF の各種のコントロール作成モデルを理解することが重要です。However, if you do need to create a new control, it is important to understand the different control authoring models in WPFWPF. WPFWPF には、コントロールを作成するための一般的なモデルが 3 つあり、各モデルはそれぞれ異なる機能と柔軟性レベルを備えています。provides three general models for creating a control, each of which provides a different set of features and level of flexibility. 3 つのモデルの基底クラスは、UserControlControlFrameworkElement です。The base classes for the three models are UserControl, Control, and FrameworkElement.

UserControl からの派生Deriving from UserControl

WPFWPF でコントロールを作成する方法で最も簡単なのは、UserControl から派生する方法です。The simplest way to create a control in WPFWPF is to derive from UserControl. UserControl を継承するコントロールを作成するときは、UserControl に既存のコンポーネントを追加し、コンポーネントに名前を付けて、Extensible Application Markup Language (XAML)Extensible Application Markup Language (XAML) でイベント ハンドラーを参照します。When you build a control that inherits from UserControl, you add existing components to the UserControl, name the components, and reference event handlers in Extensible Application Markup Language (XAML)Extensible Application Markup Language (XAML). 次に、指定の要素を参照し、コードでイベント ハンドラーを定義します。You can then reference the named elements and define the event handlers in code. この開発モデルは、WPFWPF でのアプリケーション開発に使用されるモデルとよく似ています。This development model is very similar to the model used for application development in WPFWPF.

UserControl が正しく構築されていれば、リッチ コンテンツ、スタイル、トリガーの利点を活用できます。If built correctly, a UserControl can take advantage of the benefits of rich content, styles, and triggers. ただし、UserControl を継承したコントロールの場合、そのユーザーは DataTemplate または ControlTemplate を使用して、外観をカスタマイズすることができません。However, if your control inherits from UserControl, people who use your control will not be able to use a DataTemplate or ControlTemplate to customize its appearance. Control クラスまたはその派生クラスのいずれか (UserControl 以外) から派生して、テンプレートをサポートするカスタム コントロールを作成する必要があります。It is necessary to derive from the Control class or one of its derived classes (other than UserControl) to create a custom control that supports templates.

UserControl からの派生の利点Benefits of Deriving from UserControl

次のすべての項目に該当する場合、UserControl から派生することを検討してください。Consider deriving from UserControl if all of the following apply:

  • アプリケーションの構築と同じ方法でコントロールをビルドする必要がある場合。You want to build your control similarly to how you build an application.

  • コントロールが既存のコンポーネントのみで構成されている場合。Your control consists only of existing components.

  • 複雑なカスタマイズをサポートする必要がない場合。You don't need to support complex customization.

Control からの派生Deriving from Control

Control クラスからの派生は、既存の WPFWPF コントロールの多くで使用されるモデルです。Deriving from the Control class is the model used by most of the existing WPFWPF controls. Control クラスから継承したコントロールを作成するときは、テンプレートを使用して、その外観を定義します。When you create a control that inherits from the Control class, you define its appearance by using templates. これにより、操作ロジックと視覚的表現とが分離されます。By doing so, you separate the operational logic from the visual representation. また、イベントの代わりにコマンドとバインディングを使用し、ControlTemplate での要素参照をできる限り避けることによって、UI とロジックを分離できます。You can also ensure the decoupling of the UI and logic by using commands and bindings instead of events and avoiding referencing elements in the ControlTemplate whenever possible. コントロールの UI とロジックが適切に分離されていると、コントロールのユーザーは、コントロールの ControlTemplate を再定義して、その外観をカスタマイズできます。If the UI and logic of your control are properly decoupled, a user of your control can redefine the control's ControlTemplate to customize its appearance. カスタム Control の作成は、UserControl の作成ほど単純ではありませんが、カスタム Control を使用すると、より高い柔軟性が得られます。Although building a custom Control is not as simple as building a UserControl, a custom Control provides the most flexibility.

Control からの派生の利点Benefits of Deriving from Control

次のいずれかの項目に該当する場合は、UserControl クラスを使用する代わりに、Control から派生することを検討してください。Consider deriving from Control instead of using the UserControl class if any of the following apply:

  • ControlTemplate を使用して、コントロールの外観をカスタマイズ可能にする必要がある場合。You want the appearance of your control to be customizable via the ControlTemplate.

  • コントロールがさまざまなテーマをサポートする必要がある場合。You want your control to support different themes.

FrameworkElement からの派生Deriving from FrameworkElement

UserControl または Control から派生されたコントロールは、既存の要素の構成に依存します。Controls that derive from UserControl or Control rely upon composing existing elements. 多くの状況では、それで問題ありません。FrameworkElement を継承するどのオブジェクトも ControlTemplate に含めることができるためです。For many scenarios, this is an acceptable solution, because any object that inherits from FrameworkElement can be in a ControlTemplate. しかし、場合によっては、単純な要素コンポジションでは、コントロールの外観に必要な機能を実現できないことがあります。However, there are times when a control's appearance requires more than the functionality of simple element composition. このような状況では、FrameworkElement のコンポーネントをベースにするのが適切な選択です。For these scenarios, basing a component on FrameworkElement is the right choice.

FrameworkElement ベースのコンポーネントを作成するには、ダイレクト レンダリングとカスタム要素コンポジションの 2 つの標準的な方法があります。There are two standard methods for building FrameworkElement-based components: direct rendering and custom element composition. ダイレクト レンダリングでは、FrameworkElementOnRender メソッドをオーバーライドし、コンポーネントのビジュアルを明示的に定義する DrawingContext 操作を実行します。Direct rendering involves overriding the OnRender method of FrameworkElement and providing DrawingContext operations that explicitly define the component visuals. これは、ImageBorder で使用される方法です。This is the method used by Image and Border. カスタム要素コンポジションでは、Visual 型のオブジェクトを使用して、コンポーネントの外観を構成します。Custom element composition involves using objects of type Visual to compose the appearance of your component. 例については、「DrawingVisual オブジェクトの使用」を参照してください。For an example, see Using DrawingVisual Objects. Track は、カスタム要素コンポジションを使用する WPFWPF のコントロールの例です。Track is an example of a control in WPFWPF that uses custom element composition. 同じコントロールでダイレクト レンダリングとカスタム要素コンポジションを混在させることもできます。It is also possible to mix direct rendering and custom element composition in the same control.

FrameworkElement からの派生の利点Benefits of Deriving from FrameworkElement

次のいずれかの項目に該当する場合、FrameworkElement から派生することを検討してください。Consider deriving from FrameworkElement if any of the following apply:

  • コントロールの外観について、単純な要素コンポジションが提供する以上の厳密な制御を必要とする場合。You want to have precise control over the appearance of your control beyond what is provided by simple element composition.

  • 独自のレンダリング ロジックを定義して、コントロールの外観を定義する必要がある場合。You want to define the appearance of your control by defining your own render logic.

  • UserControl および Control を使用する方法では実現できない新しい方法で既存の要素を構成する必要がある場合。You want to compose existing elements in novel ways that go beyond what is possible with UserControl and Control.

コントロール作成の基本Control Authoring Basics

既に説明したように、WPFWPF の最も強力な機能の 1 つは、コントロールの基本的なプロパティ設定だけでは不可能な外観や動作の変更を実現し、しかもカスタム コントロールを作成する必要がないということです。As discussed earlier, one of the most powerful features of WPFWPF is the ability to go beyond setting basic properties of a control to change its appearance and behavior, yet still not needing to create a custom control. スタイル設定、データ バインディング、トリガーの各機能は、WPFWPF プロパティ システムおよび WPFWPF イベント システムによって実現されています。The styling, data binding, and trigger features are made possible by the WPFWPF property system and the WPFWPF event system. 以降のセクションでは、カスタム コントロールのユーザーが、WPFWPF に付属のコントロールと同じように、これらの機能を使用できるようにするために、カスタム コントロールの作成に使用するモデルに関係なく、従う必要があるプラクティスについて説明します。The following sections describe some practices that you should follow, regardless of the model you use to create the custom control, so that users of your custom control can use these features just as they would for a control that is included with WPFWPF.

依存関係プロパティの使用Use Dependency Properties

プロパティが依存関係プロパティである場合、以下の操作が可能です。When a property is a dependency property, it is possible to do the following:

  • スタイルのプロパティを設定する。Set the property in a style.

  • プロパティをデータ ソースにバインドする。Bind the property to a data source.

  • プロパティの値として、動的リソースを使用する。Use a dynamic resource as the property's value.

  • プロパティ名をアニメーション化する。Animate the property.

コントロールのプロパティがこれらの機能のいずれかをサポートす必要がある場合、それを依存関係プロパティとして実装する必要があります。If you want a property of your control to support any of this functionality, you should implement it as a dependency property. 次の例では、以下の処理を実行して、Value という名前の依存関係プロパティを定義します。The following example defines a dependency property named Value by doing the following:

  • ValueProperty という名前の DependencyProperty 識別子を、public static readonly フィールドとして定義します。Define a DependencyProperty identifier named ValueProperty as a public static readonly field.

  • DependencyProperty.Register を呼び出して、プロパティ システムにプロパティ名を登録し、次の項目を指定します。Register the property name with the property system, by calling DependencyProperty.Register, to specify the following:

    • プロパティの名前。The name of the property.

    • プロパティの型。The type of the property.

    • プロパティを所有する型。The type that owns the property.

    • プロパティのメタデータ。The metadata for the property. メタデータには、プロパティの既定値、CoerceValueCallback および PropertyChangedCallback が含まれています。The metadata contains the property's default value, a CoerceValueCallback and a PropertyChangedCallback.

  • プロパティの get アクセサーと set アクセサーを実装することにより、依存関係プロパティの登録名と同じ Value という名前で CLR ラッパー プロパティを定義します。Define a CLR wrapper property named Value, which is the same name that is used to register the dependency property, by implementing the property's get and set accessors. get アクセサーと set アクセサーは、それぞれ GetValueSetValue しか呼び出すことができないことに注意してください。Note that the get and set accessors only call GetValue and SetValue respectively. 依存関係プロパティのアクセサーには、その他のロジックを含めないことをお勧めします。クライアントおよび WPFWPF では、アクセサーが省略され、GetValueSetValue が直接呼び出されることがあるためです。It is recommended that the accessors of dependency properties not contain additional logic because clients and WPFWPF can bypass the accessors and call GetValue and SetValue directly. たとえば、プロパティがデータ ソースにバインドされている場合、プロパティの set アクセサーは呼び出されません。For example, when a property is bound to a data source, the property's set accessor is not called. get アクセサーと set アクセサーに他のロジックを追加するのではなく、ValidateValueCallbackCoerceValueCallback、および PropertyChangedCallback の各デリゲートを使用して、値の変更時に応答したり、値を確認したりします。Instead of adding additional logic to the get and set accessors, use the ValidateValueCallback, CoerceValueCallback, and PropertyChangedCallback delegates to respond to or check the value when it changes. これらのコールバックの詳細については、「依存関係プロパティのコールバックと検証」を参照してください。For more information on these callbacks, see Dependency Property Callbacks and Validation.

  • CoerceValueCallback に対応する、CoerceValue という名前のメソッドを定義します。Define a method for the CoerceValueCallback named CoerceValue. CoerceValue によって、ValueMinValue 以上で MaxValue 以下になります。CoerceValue ensures that Value is greater or equal to MinValue and less than or equal to MaxValue.

  • PropertyChangedCallback に対応する、OnValueChanged という名前のメソッドを定義します。Define a method for the PropertyChangedCallback, named OnValueChanged. OnValueChanged では、RoutedPropertyChangedEventArgs<T> オブジェクトが作成され、ValueChanged ルーティング イベントの生成が準備されます。OnValueChanged creates a RoutedPropertyChangedEventArgs<T> object and prepares to raise the ValueChanged routed event. ルーティング イベントについては、次のセクションで説明します。Routed events are discussed in the next section.

/// <summary>
/// Identifies the Value dependency property.
/// </summary>
public static readonly DependencyProperty ValueProperty =
        "Value", typeof(decimal), typeof(NumericUpDown),
        new FrameworkPropertyMetadata(MinValue, new PropertyChangedCallback(OnValueChanged),
                                      new CoerceValueCallback(CoerceValue)));

/// <summary>
/// Gets or sets the value assigned to the control.
/// </summary>
public decimal Value
    get { return (decimal)GetValue(ValueProperty); }
    set { SetValue(ValueProperty, value); }

private static object CoerceValue(DependencyObject element, object value)
    decimal newValue = (decimal)value;
    NumericUpDown control = (NumericUpDown)element;

    newValue = Math.Max(MinValue, Math.Min(MaxValue, newValue));

    return newValue;

private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    NumericUpDown control = (NumericUpDown)obj;			

    RoutedPropertyChangedEventArgs<decimal> e = new RoutedPropertyChangedEventArgs<decimal>(
        (decimal)args.OldValue, (decimal)args.NewValue, ValueChangedEvent);
''' <summary>
''' Identifies the Value dependency property.
''' </summary>
Public Shared ReadOnly ValueProperty As DependencyProperty = DependencyProperty.Register("Value", GetType(Decimal), GetType(NumericUpDown), New FrameworkPropertyMetadata(MinValue, New PropertyChangedCallback(AddressOf OnValueChanged), New CoerceValueCallback(AddressOf CoerceValue)))

''' <summary>
''' Gets or sets the value assigned to the control.
''' </summary>
Public Property Value() As Decimal
        Return CDec(GetValue(ValueProperty))
    End Get
    Set(ByVal value As Decimal)
        SetValue(ValueProperty, value)
    End Set
End Property

Private Shared Overloads Function CoerceValue(ByVal element As DependencyObject, ByVal value As Object) As Object
    Dim newValue As Decimal = CDec(value)
    Dim control As NumericUpDown = CType(element, NumericUpDown)

    newValue = Math.Max(MinValue, Math.Min(MaxValue, newValue))

    Return newValue
End Function

Private Shared Sub OnValueChanged(ByVal obj As DependencyObject, ByVal args As DependencyPropertyChangedEventArgs)
    Dim control As NumericUpDown = CType(obj, NumericUpDown)

    Dim e As New RoutedPropertyChangedEventArgs(Of Decimal)(CDec(args.OldValue), CDec(args.NewValue), ValueChangedEvent)
End Sub

詳細については、「カスタム依存関係プロパティ」を参照してください。For more information, see Custom Dependency Properties.

ルーティング イベントの使用Use Routed Events

依存関係プロパティで CLR プロパティの概念が追加機能によって拡張されるのと同様に、ルーティング イベントでは、標準の CLR イベントの概念が拡張されます。Just as dependency properties extend the notion of CLR properties with additional functionality, routed events extend the notion of standard CLR events. 新しい WPFWPF コントロール作成する場合、イベントをルーティング イベントとして実装することをお勧めします。ルーティング イベントは以下の機能をサポートしているためです。When you create a new WPFWPF control, it is also good practice to implement your event as a routed event because a routed event supports the following behavior:

  • 複数のコントロールの親でイベントを処理できます。Events can be handled on a parent of multiple controls. イベントがバブル イベントの場合、要素ツリー内の単一の親はイベントをサブスクライブできます。If an event is a bubbling event, a single parent in the element tree can subscribe to the event. これにより、アプリケーション開発者は、複数のコントロールのイベントに 1 つのハンドラーで対応できます。Then application authors can use one handler to respond to the event of multiple controls. たとえば、ListBox の各項目に含まれるコントロール (DataTemplate に含まれているため) の場合、アプリケーション開発者は、コントロールのイベントに対応するイベント ハンドラーを ListBox で定義できます。For example, if your control is a part of each item in a ListBox (because it is included in a DataTemplate), the application developer can define the event handler for your control's event on the ListBox. いずれかのコントロールでイベントが発生するたびに、そのイベント ハンドラーが呼び出されます。Whenever the event occurs on any of the controls, the event handler is called.

  • ルーティング イベントは EventSetter で使用できます。これにより、アプリケーション開発者はイベントのハンドラーをスタイル内で指定できます。Routed events can be used in an EventSetter, which enables application developers to specify the handler of an event within a style.

  • ルーティング イベントは EventTrigger で使用でき、XAMLXAML を使用したプロパティのアニメーション化に役立ちます。Routed events can be used in an EventTrigger, which is useful for animating properties by using XAMLXAML. 詳しくは、「 アニメーションの概要」をご覧ください。For more information, see Animation Overview.

次に示す例では、以下の処理を実行して、ルーティング イベントを定義します。The following example defines a routed event by doing the following:

  • ValueChangedEvent という名前の RoutedEvent 識別子を、public static readonly フィールドとして定義します。Define a RoutedEvent identifier named ValueChangedEvent as a public static readonly field.

  • EventManager.RegisterRoutedEvent メソッドを呼び出して、ルーティング イベントを登録します。Register the routed event by calling the EventManager.RegisterRoutedEvent method. この例では、RegisterRoutedEvent を呼び出すときに、次の情報を指定します。The example specifies the following information when it calls RegisterRoutedEvent:

    • イベントの名前が ValueChanged であること。The name of the event is ValueChanged.

    • ルーティング方法が Bubble であること。ソース (イベントを発生させるオブジェクト) のイベント ハンドラーがまず呼び出され、その後、ソースの親要素のイベント ハンドラーが、最も近い親要素のイベント ハンドラーから順に呼び出されるルーティング方法です。The routing strategy is Bubble, which means that an event handler on the source (the object that raises the event) is called first, and then event handlers on the source's parent elements are called in succession, starting with the event handler on the closest parent element.

    • イベント ハンドラーの型が RoutedPropertyChangedEventHandler<T> で、Decimal 型で構築されていること。The type of the event handler is RoutedPropertyChangedEventHandler<T>, constructed with a Decimal type.

    • イベントを所有する型が NumericUpDown であること。The owning type of the event is NumericUpDown.

  • ValueChanged という名前のパブリック イベントを宣言し、イベント アクセサー宣言を含めます。Declare a public event named ValueChanged and includes event-accessor declarations. この例では、add アクセサー宣言で AddHandler を、remove アクセサーの宣言で RemoveHandler をそれぞれ呼び出して、WPFWPF イベント サービスを使用します。The example calls AddHandler in the add accessor declaration and RemoveHandler in the remove accessor declaration to use the WPFWPF event services.

  • ValueChangedイベントを発生させる、保護された仮想メソッド OnValueChanged を作成します。Create a protected, virtual method named OnValueChanged that raises the ValueChanged event.

/// <summary>
/// Identifies the ValueChanged routed event.
/// </summary>
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent(
    "ValueChanged", RoutingStrategy.Bubble,
    typeof(RoutedPropertyChangedEventHandler<decimal>), typeof(NumericUpDown));

/// <summary>
/// Occurs when the Value property changes.
/// </summary>
public event RoutedPropertyChangedEventHandler<decimal> ValueChanged
    add { AddHandler(ValueChangedEvent, value); }
    remove { RemoveHandler(ValueChangedEvent, value); }

/// <summary>
/// Raises the ValueChanged event.
/// </summary>
/// <param name="args">Arguments associated with the ValueChanged event.</param>
protected virtual void OnValueChanged(RoutedPropertyChangedEventArgs<decimal> args)
''' <summary>
''' Identifies the ValueChanged routed event.
''' </summary>
Public Shared ReadOnly ValueChangedEvent As RoutedEvent = EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, GetType(RoutedPropertyChangedEventHandler(Of Decimal)), GetType(NumericUpDown))

''' <summary>
''' Occurs when the Value property changes.
''' </summary>
Public Custom Event ValueChanged As RoutedPropertyChangedEventHandler(Of Decimal)
    AddHandler(ByVal value As RoutedPropertyChangedEventHandler(Of Decimal))
        MyBase.AddHandler(ValueChangedEvent, value)
    End AddHandler
    RemoveHandler(ByVal value As RoutedPropertyChangedEventHandler(Of Decimal))
        MyBase.RemoveHandler(ValueChangedEvent, value)
    End RemoveHandler
    RaiseEvent(ByVal sender As System.Object, ByVal e As RoutedPropertyChangedEventArgs(Of Decimal))
    End RaiseEvent
End Event

''' <summary>
''' Raises the ValueChanged event.
''' </summary>
''' <param name="args">Arguments associated with the ValueChanged event.</param>
Protected Overridable Sub OnValueChanged(ByVal args As RoutedPropertyChangedEventArgs(Of Decimal))
End Sub

詳細については、「ルーティング イベントの概要」および「カスタム ルーティング イベントを作成する」を参照してください。For more information, see Routed Events Overview and Create a Custom Routed Event.

バインディングの使用Use Binding

コントロールの UI とロジックを分離するには、データ バインディングを使用する方法もあります。To decouple the UI of your control from its logic, consider using data binding. これは、ControlTemplate を使用してコントロールの外観を定義する場合に、特に重要です。This is particularly important if you define the appearance of your control by using a ControlTemplate. データ バインディングを使用すると、コードから UI の特定の部分を参照する必要性がなくなる場合があります。When you use data binding, you might be able to eliminate the need to reference specific parts of the UI from the code. ControlTemplate 内の要素の参照を避けることをお勧めします。コードで ControlTemplate 内の要素を参照する場合、ControlTemplate が変更されたときに、新しい ControlTemplate に参照先の要素を含める必要があるためです。It's a good idea to avoid referencing elements that are in the ControlTemplate because when the code references elements that are in the ControlTemplate and the ControlTemplate is changed, the referenced element needs to be included in the new ControlTemplate.

次の例では、NumericUpDown コントロールの TextBlock を更新し、名前を割り当てて、コード内の名前を使用してテキスト ボックスを参照しています。The following example updates the TextBlock of the NumericUpDown control, assigning a name to it and referencing the textbox by name in code.

<Border BorderThickness="1" BorderBrush="Gray" Margin="2" 
        Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Stretch">
  <TextBlock Name="valueText" Width="60" TextAlignment="Right" Padding="5"/>
private void UpdateTextBlock()
    valueText.Text = Value.ToString();
Private Sub UpdateTextBlock()
    valueText.Text = Value.ToString()
End Sub

次の例では、バインディングを使用して同じことを実現しています。The following example uses binding to accomplish the same thing.

<Border BorderThickness="1" BorderBrush="Gray" Margin="2" 
        Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Stretch">

    <!--Bind the TextBlock to the Value property-->
        Width="60" TextAlignment="Right" Padding="5"
        Text="{Binding RelativeSource={RelativeSource FindAncestor, 
                       AncestorType={x:Type local:NumericUpDown}}, 


データ バインディングの詳細については、「データ バインディングの概要」を参照してください。For more information about data binding, see Data Binding Overview.

デザイナーに対応したデザインDesign for Designers

Visual Studio 用の WPF デザイナーでカスタム WPF コントロールのサポート (たとえば、[プロパティ] ウィンドウでのプロパティ編集) を利用するには、以下のガイドラインに従います。To receive support for custom WPF controls in the WPF Designer for Visual Studio (for example, property editing with the Properties window), follow these guidelines. WPF デザイナーでの開発の詳細については、「Visual Studio で XAML をデザインする」を参照してください。For more information on developing for the WPF Designer, see Design XAML in Visual Studio.

依存関係プロパティDependency Properties

「依存関係プロパティの使用」で説明したように、CLR の get アクセサーと set アクセサーを実装します。Be sure to implement CLR get and set accessors as described earlier, in "Use Dependency Properties." デザイナーは、ラッパーを使用して依存関係プロパティの存在を検出する場合がありますが、WPFWPF およびコントロールのクライアントと同様、プロパティを取得または設定するときにアクセサーを呼び出す必要はありません。Designers may use the wrapper to detect the presence of a dependency property, but they, like WPFWPF and clients of the control, are not required to call the accessors when getting or setting the property.

アタッチされるプロパティAttached Properties

以下のガイドラインに従って、カスタム コントロールに添付プロパティを実装する必要があります。You should implement attached properties on custom controls using the following guidelines:

  • PropertyNameProperty という形式の public static readonly DependencyProperty を、RegisterAttached メソッドを使用して作成します。Have a public static readonly DependencyProperty of the form PropertyNameProperty that was creating using the RegisterAttached method. RegisterAttached に渡されるプロパティ名は、PropertyName と一致している必要があります。The property name that is passed to RegisterAttached must match PropertyName.

  • SetPropertyName および GetPropertyName という名前の public static CLR メソッドのペアを実装します。Implement a pair of public static CLR methods named SetPropertyName and GetPropertyName. いずれのメソッドでも、DependencyProperty の派生クラスを最初の引数として受け取る必要があります。Both methods should accept a class derived from DependencyProperty as their first argument. また、SetPropertyName メソッドでは、プロパティの登録データ型と同じ型の引数も受け取ります。The SetPropertyName method also accepts an argument whose type matches the registered data type for the property. GetPropertyNameメソッドでは、同じ型の値を返す必要があります。The GetPropertyName method should return a value of the same type. SetPropertyNameメソッドがない場合、プロパティは読み取り専用としてマークされます。If the SetPropertyName method is missing, the property is marked read-only.

  • SetPropertyName および GetPropertyName は、それぞれ、対象の依存関係オブジェクトの GetValue メソッドおよび SetValue メソッドのに直接転送する必要があります。Set PropertyName and GetPropertyName must route directly to the GetValue and SetValue methods on the target dependency object, respectively. デザイナーが添付プロパティにアクセスするには、メソッド ラッパー経由で呼び出す場合もあれば、対象の依存関係オブジェクトを直接呼び出す場合もあります。Designers may access the attached property by calling through the method wrapper or making a direct call to the target dependency object.

添付プロパティの詳細については、「添付プロパティの概要」を参照してください。For more information on attached properties, see Attached Properties Overview.

共有リソースの定義と使用Define and Use Shared Resources

アプリケーションと同じアセンブリにコントロールを含めることも、複数のアプリケーションが使用できる別のアセンブリにコントロールをパッケージ化することもできます。You can include your control in the same assembly as your application, or you can package your control in a separate assembly that can be used in multiple applications. このトピックで説明した情報の大部分は、使用する方法に関係なく適用されます。For the most part, the information discussed in this topic applies regardless of the method you use. ただし、1 つだけ例外があります。There is one difference worth noting, however. アプリケーションと同じアセンブリ内にコントロールを配置する場合、App.xaml ファイルにグローバル リソースを自由に追加できます。When you put a control in the same assembly as an application, you are free to add global resources to the App.xaml file. しかし、コントロールだけを含むアセンブリには、Application オブジェクトが関連付けられないため、App.xaml ファイルは使用できません。But an assembly that contains only controls does not have an Application object associated with it, so an App.xaml file is not available.

アプリケーションがリソースを検索するときは、次に示す順序で 3 つのレベルを検索します。When an application looks for a resource, it looks at three levels in the following order:

  1. 要素レベル。The element level.

    システムは、リソースを参照する要素から検索を開始し、ルート要素に到達するまで、論理上の親のリソースの検索を継続します。The system starts with the element that references the resource and then searches resources of the logical parent and so forth until the root element is reached.

  2. アプリケーション レベル。The application level.

    Application オブジェクトで定義されたリソース。Resources defined by the Application object.

  3. テーマ レベル。The theme level.

    テーマ レベルのディクショナリは、Themes という名前のサブフォルダーに格納されています。Theme-level dictionaries are stored in a subfolder named Themes. Themes フォルダー内のファイルはテーマに対応しています。The files in the Themes folder correspond to themes. たとえば、Aero.NormalColor.xaml、Luna.NormalColor.xaml、Royale.NormalColor.xaml などのファイルがあります。For example, you might have Aero.NormalColor.xaml, Luna.NormalColor.xaml, Royale.NormalColor.xaml, and so on. generic.xaml という名前のファイルが含まれている場合もあります。You can also have a file named generic.xaml. システムがテーマ レベルでリソースを検索するとき、最初にテーマ固有のファイル内を検索し、次に generic.xaml 内を検索します。When the system looks for a resource at the themes level, it first looks for it in the theme-specific file and then looks for it in generic.xaml.

アプリケーションとは別のアセンブリ内にコントロールを含めるときは、グローバル リソースを要素レベルまたはテーマ レベルに配置する必要があります。When your control is in an assembly that is separate from the application, you must put your global resources at the element level or at the theme level. どちらに配置する場合も、それぞれの利点があります。Both methods have their advantages.

要素レベルでのリソース定義Defining Resources at the Element Level

カスタムのリソース ディクショナリを作成し、それをコントロールのリソース ディクショナリと結合することによって、共有リソースを要素レベルで定義できます。You can define shared resources at the element level by creating a custom resource dictionary and merging it with your control's resource dictionary. このメソッドで定義する場合は、リソース ファイルに任意の名前を付けて、コントロールと同じフォルダーに配置できます。When you use this method, you can name your resource file anything you want, and it can be in the same folder as your controls. 要素レベルでのリソースでは、単純な文字列をキーとして使用することもできます。Resources at the element level can also use simple strings as keys. 次の例では、Dictionary1.xaml という名前の LinearGradientBrush リソース ファイルを作成します。The following example creates a LinearGradientBrush resource file named Dictionary1.xaml.

    StartPoint="0,0" EndPoint="1,1">
    <GradientStop Color="Red" Offset="0.25" />
    <GradientStop Color="Blue" Offset="0.75" />

ディクショナリを定義したら、それをコントロールのリソース ディクショナリにマージする必要があります。Once you have defined your dictionary, you need to merge it with your control's resource dictionary. これには、XAMLXAML またはコードを使用します。You can do this by using XAMLXAML or code.

次の例では、XAMLXAML を使用してリソース ディクショナリを結合します。The following example merges a resource dictionary by using XAMLXAML.

            <ResourceDictionary Source="Dictionary1.xaml"/>

この方法の欠点は、参照するたびに ResourceDictionary オブジェクトが作成されることです。The disadvantage to this approach is that a ResourceDictionary object is created each time you reference it. たとえば、ライブラリ内に 10 個のカスタム コントロールがあり、XAML を使用して各コントロール用の共有リソース ディクショナリを結合する場合、同一の ResourceDictionary オブジェクトが 10 個作成されます。For example, if you have 10 custom controls in your library and merge the shared resource dictionaries for each control by using XAML, you create 10 identical ResourceDictionary objects. これを回避するには、コード内でリソースを結合し、結果として作成される ResourceDictionary を返す、静的クラスを作成します。You can avoid this by creating a static class that merges the resources in code and returns the resulting ResourceDictionary.

次の例では、共有の ResourceDictionary を返すクラスを作成します。The following example creates a class that returns a shared ResourceDictionary.

internal static class SharedDictionaryManager
    internal static ResourceDictionary SharedDictionary
            if (_sharedDictionary == null)
                System.Uri resourceLocater =
                    new System.Uri("/ElementResourcesCustomControlLibrary;component/Dictionary1.xaml",

                _sharedDictionary =

            return _sharedDictionary;

    private static ResourceDictionary _sharedDictionary;

次の例では、InitializeComponent を呼び出す前に、共有リソースをコントロールのコンス トラクター内でカスタム コントロールのリソースと結合します。The following example merges the shared resource with the resources of a custom control in the control's constructor before it calls InitializeComponent. SharedDictionaryManager.SharedDictionary は静的プロパティであるため、ResourceDictionary が作成されるのは 1 回だけです。Because the SharedDictionaryManager.SharedDictionary is a static property, the ResourceDictionary is created only once. InitializeComponent が呼び出される前に、リソース ディクショナリが結合されため、コントロールは XAMLXAML ファイル内でリソースを使用できます。Because the resource dictionary was merged before InitializeComponent was called, the resources are available to the control in its XAMLXAML file.

public NumericUpDown()

テーマ レベルでのリソース定義Defining Resources at the Theme Level

WPFWPF では、さまざまな Windows テーマ用にリソースを作成できます。enables you to create resources for different Windows themes. コントロールの作成者は、特定のテーマ用のリソースを定義して、使用するテーマに応じてコントロールの外観を変更できます。As a control author, you can define a resource for a specific theme to change your control's appearance depending on what theme is in use. たとえば、Windows クラシックのテーマ (Windows 2000 の既定のテーマ) での Button の外観は、Windows Luna テーマ (Windows XP の既定のテーマ) での Button とは異なります。これは、Button では、テーマごとに異なる ControlTemplate が使用されるためです。For example, the appearance of a Button in the Windows Classic theme (the default theme for Windows 2000) differs from a Button in the Windows Luna theme (the default theme for Windows XP) because the Button uses a different ControlTemplate for each theme.

テーマ固有のリソースは、固有のファイル名でリソース ディクショナリに保持されます。Resources that are specific to a theme are kept in a resource dictionary with a specific file name. これらのファイルは、コントロールが格納されているフォルダーのサブフォルダーである Themes フォルダー内に配置する必要があります。These files must be in a folder named Themes that is a subfolder of the folder that contains the control. 次の表は、リソース ディクショナリ ファイルと、各ファイルに関連付けられているテーマを示しています。The following table lists the resource dictionary files and the theme that is associated with each file:

リソース ディクショナリ ファイル名Resource dictionary file name Windows テーマWindows theme
Classic.xaml Windows XP のクラシックな Windows 9x/2000 の外観Classic Windows 9x/2000 look on Windows XP
Luna.NormalColor.xaml Windows XP の既定の青のテーマDefault blue theme on Windows XP
Luna.Homestead.xaml Windows XP のオリーブのテーマOlive theme on Windows XP
Luna.Metallic.xaml Windows XP のシルバーのテーマSilver theme on Windows XP
Royale.NormalColor.xaml Windows XP Media Center Edition の既定テーマDefault theme on Windows XP Media Center Edition
Aero.NormalColor.xaml Windows Vista の既定テーマDefault theme on Windows Vista

すべてのテーマのリソースを定義する必要はありません。You do not need to define a resource for every theme. 特定のテーマについてリソースが定義されていない場合、コントロールはリソースの Classic.xaml を確認します。If a resource is not defined for a specific theme, then the control checks Classic.xaml for the resource. 現在のテーマに対応するファイルや Classic.xaml でリソースが定義されていない場合、コントロールは汎用のリソースを使用します。汎用のリソースは、generic.xaml という名前のリソース ディクショナリ ファイルにあります。If the resource is not defined in the file that corresponds to the current theme or in Classic.xaml, the control uses the generic resource, which is in a resource dictionary file named generic.xaml. generic.xaml ファイルは、テーマ固有のリソース ディクショナリ ファイルと同じフォルダーに配置されています。The generic.xaml file is located in the same folder as the theme-specific resource dictionary files. generic.xaml は、特定の Windows テーマには対応していませんが、テーマ レベルのディクショナリであることに変わりありません。Although generic.xaml does not correspond to a specific Windows theme, it is still a theme-level dictionary.

C# または Visual Basic の、テーマおよび UI オートメーションがサポートされた NumericUpDown カスタム コントロールのサンプルには、NumericUpDown コントロール用の 2 つのリソース ディクショナリが含まれています。1 つは generic.xaml で、もう 1 つは Luna.NormalColor.xaml です。The C# or Visual Basic NumericUpDown custom control with theme and UI automation support sample contains two resource dictionaries for the NumericUpDown control: one is in generic.xaml, and the other is in Luna.NormalColor.xaml.

テーマ固有のリソース ディクショナリ ファイルのいずれかに ControlTemplate を配置する場合、次の例に示すように、コントロール用の静的コンストラクターを作成し、DefaultStyleKeyOverrideMetadata(Type, PropertyMetadata) メソッドを呼び出す必要があります。When you put a ControlTemplate in any of the theme-specific resource dictionary files, you must create a static constructor for your control and call the OverrideMetadata(Type, PropertyMetadata) method on the DefaultStyleKey, as shown in the following example.

static NumericUpDown()
               new FrameworkPropertyMetadata(typeof(NumericUpDown)));
Shared Sub New()
    DefaultStyleKeyProperty.OverrideMetadata(GetType(NumericUpDown), New FrameworkPropertyMetadata(GetType(NumericUpDown)))
End Sub
テーマ リソース用のキーの定義と参照Defining and Referencing Keys for Theme Resources

要素レベルでリソースを定義するときに、文字列をキーとして割り当て、その文字列を使用してリソースにアクセスできます。When you define a resource at the element level, you can assign a string as its key and access the resource via the string. テーマ レベルでリソースを定義するときは、ComponentResourceKey をキーとして使用する必要があります。When you define a resource at the theme level, you must use a ComponentResourceKey as the key. 次の例では、generic.xaml でリソースを定義します。The following example defines a resource in generic.xaml.

     x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:Painter}, 
                                  StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="Blue" Offset="0" />
    <GradientStop Color="Red" Offset="0.5" />
    <GradientStop Color="Green" Offset="1"/>

次の例では、ComponentResourceKey をキーとして指定して、リソースを参照します。The following example references the resource by specifying the ComponentResourceKey as the key.

    Grid.Column="1" Grid.Row="0"
    Background="{StaticResource {ComponentResourceKey 
                        TypeInTargetAssembly={x:Type local:NumericUpDown}, 
    Grid.Column="1" Grid.Row="1"
    Background="{StaticResource {ComponentResourceKey 
                    TypeInTargetAssembly={x:Type local:NumericUpDown}, 
テーマ リソースの場所の指定Specifying the Location of Theme Resources

コントロールのリソースを見つけるには、アセンブリにコントロール固有のリソースが含まれていることを、ホスト アプリケーションが認識する必要があります。To find the resources for a control, the hosting application needs to know that the assembly contains control-specific resources. これを可能にするには、コントロールが含まれているアセンブリに ThemeInfoAttribute を追加します。You can accomplish that by adding the ThemeInfoAttribute to the assembly that contains the control. ThemeInfoAttribute には、汎用のリソースの場所を指定する GenericDictionaryLocation プロパティと、テーマ固有のリソースの場所を指定する ThemeDictionaryLocation プロパティがあります。The ThemeInfoAttribute has a GenericDictionaryLocation property that specifies the location of generic resources, and a ThemeDictionaryLocation property that specifies the location of the theme-specific resources.

次の例では、GenericDictionaryLocation プロパティと ThemeDictionaryLocation プロパティを SourceAssembly に設定し、汎用リソースとテーマ固有のリソースがコントロールと同じアセンブリ内にあることを指定しています。The following example sets the GenericDictionaryLocation and ThemeDictionaryLocation properties to SourceAssembly, to specify that the generic and theme-specific resources are in the same assembly as the control.

[assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly,
<Assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly, ResourceDictionaryLocation.SourceAssembly)>

関連項目See also