コントロールの作成の概要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. AStyleはコントロールのプロパティを表す値のコレクションです。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. ADataTemplateコントロールにデータを表示する方法をカスタマイズすることができます。A DataTemplate enables you to customize how data is displayed on a control. たとえば、DataTemplateにデータを表示する方法を指定するために使用できる、 ListBoxFor 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使用できる、 DataTemplateDataTemplateはこの例では不十分です。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. ATrigger新しいコントロールを作成せず、コントロールの動作と外観を動的に変更することができます。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 つのモデルはUserControlControl、およびFrameworkElementします。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. イベントと回避の参照元要素ではなく、コマンドとバインディングを使用して、UI とロジックの分離も確認できます、ControlTemplate可能な場合。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

派生することを検討してくださいControlを使用してではなく、UserControlクラスの場合、以下が適用されます。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.

ビルドするための 2 つの標準的なメソッドがあるFrameworkElement-ベースのコンポーネント: レンダリングとカスタム要素コンポジションをダイレクトします。There are two standard methods for building FrameworkElement-based components: direct rendering and custom element composition. ダイレクト レンダリングでは、オーバーライド、OnRenderメソッドのFrameworkElementおり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.

  • 使って何ができる上回る斬新な方法で既存の要素を作成するUserControlControlします。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:

  • 定義、DependencyPropertyという名前の識別子ValuePropertyとして、 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. メタデータにはプロパティの既定値が含まれています、CoerceValueCallbackPropertyChangedCallbackします。The metadata contains the property's default value, a CoerceValueCallback and a PropertyChangedCallback.

  • プロパティの get アクセサーと set アクセサーを実装することにより、依存関係プロパティの登録名と同じ Value という名前で CLRCLR ラッパー プロパティを定義します。Define a CLRCLR 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. なお、getsetアクセサーのみを呼び出す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. 取得する追加のロジックを追加する代わりに、set アクセサーは、使用、 ValidateValueCallbackCoerceValueCallbackPropertyChangedCallbackデリゲートに応答したり、変更するときに、値を確認します。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

依存関係プロパティが CLRCLR プロパティの概念を追加機能によって拡張するのと同様に、ルーティング イベントは、標準の CLRCLR イベントの概念を拡張します。Just as dependency properties extend the notion of CLRCLR properties with additional functionality, routed events extend the notion of standard CLRCLR 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:

  • 定義、RoutedEventという名前の識別子ValueChangedEventとして、 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. 例では、AddHandlerで、addアクセサーの宣言とRemoveHandlerで、removeアクセサーの宣言を使用する、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ため、コードが含まれている要素を参照するときに、ControlTemplateControlTemplateが変更されると、新しいに含まれる参照先の要素のニーズ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.

次の例の更新プログラム、TextBlockNumericUpDownコントロールにその名前を割り当てると、コード内の名前をテキスト ボックスの参照します。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

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

依存関係プロパティDependency Properties

「依存関係プロパティの使用」で説明したように、CLRCLRget アクセサーと set アクセサーを実装します。Be sure to implement CLRCLR 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:

  • public static readonly DependencyPropertyフォームのPropertyName Propertyを使用して作成された、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.

  • Set PropertyName および Get PropertyName という名前の 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. また、Set PropertyName メソッドでは、プロパティの登録データ型と同じ型の引数も受け取ります。The SetPropertyName method also accepts an argument whose type matches the registered data type for the property. Get PropertyNameメソッドでは、同じ型の値を返す必要があります。The GetPropertyName method should return a value of the same type. Set PropertyNameメソッドがない場合、プロパティは読み取り専用としてマークされます。If the SetPropertyName method is missing, the property is marked read-only.

  • Set PropertyNameGet PropertyNameに直接ルーティングする必要があります、GetValueSetValueオブジェクトのメソッド ターゲット依存関係に、それぞれします。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. 次の例では、作成、 LinearGradientBrush Dictionary1.xaml という名前のリソース ファイル。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 を使用して各コントロールの共有リソース ディクショナリをマージして場合を作成する 10 同一ResourceDictionaryオブジェクト。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. 外観など、 Button Windows クラシックのテーマ (Windows 2000 の既定のテーマ) とは異なります、 Button Windows Luna テーマ (Windows XP の既定のテーマ) のため、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.

テーマおよび UI オートメーションがサポートされた NumericUpDown カスタム コントロールのサンプルには、NumericUpDown コントロール用の 2 つのリソース ディクショナリが含まれています。1 つは generic.xaml で、もう 1 つは Luna.NormalColor.xaml です。NumericUpDown Custom Control with Theme and UI Automation Support Sample contains two resource dictionaries for the NumericUpDown control: one is in generic.xaml and one is in Luna.NormalColor.xaml. アプリケーションを実行し、Windows XP のシルバーのテーマと別のテーマを切り替えて、2 つのコントロール テンプレートの違いを確認できます。You can run the application and switch between the Silver theme in Windows XP and another theme to see the difference between the two control templates. (Windows Vista を使用している場合は、Luna.NormalColor.xaml を Aero.NormalColor.xaml という名前に変更し、Windows クラシック テーマと Windows Vista の既定のテーマなど、2 つのテーマを切り替えることができます)。(If you are running Windows Vista, you can rename Luna.NormalColor.xaml to Aero.NormalColor.xaml and switch between two themes, such as Windows Classic and the default theme for Windows Vista.)

配置すると、 ControlTemplate 、テーマ固有のリソース ディクショナリ ファイルのいずれのコントロールと呼び出しの静的コンス トラクターを作成する必要があります、OverrideMetadata(Type, PropertyMetadata)メソッドをDefaultStyleKey次の例のようにします。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.

次の例のセット、GenericDictionaryLocationThemeDictionaryLocationプロパティを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