次の方法で共有


WPF カスタム コントロールの UI オートメーション

更新 : 2010 年 12 月

Microsoft UI Automationは、オートメーション クライアントが各種のプラットフォームおよびフレームワークのユーザー インターフェイスを確認または操作するときに使用できる、単一の汎用的なインターフェイスを提供します。 UI Automationによって、品質保証 (テスト) のためのコードと、スクリーン リーダーなどのユーザー補助アプリケーションの両方で、ユーザー インターフェイス要素をチェックし、ユーザーによる別のコードからのそれらの要素の操作をシミュレーションできます。 各種プラットフォームでの UI Automationの詳細については、「ユーザー補助」を参照してください。

ここでは、WPF アプリケーションで実行されるカスタム コントロール用にサーバー側の UI オートメーション プロバイダーを実装する方法について説明します。 WPF では、ユーザー インターフェイス要素のツリーに対応するピア オートメーション オブジェクトのツリーを使用して、UI Automationをサポートします。 テスト コードや、ユーザー補助機能を提供するアプリケーションは、ピア オブジェクトを直接使用することも (インプロセス コードの場合)、UI Automationが提供する汎用のインターフェイスをとおして使用することもできます。

このトピックは、次のセクションで構成されています。

  • オートメーション ピア クラス
  • 組み込みのオートメーション ピア クラス
  • 派生ピアのセキュリティに関する考慮事項
  • ピアのナビゲーション
  • 派生ピアでのカスタマイズ
  • 関連トピック

オートメーション ピア クラス

WPF では、AutomationPeer から派生するピア クラスのツリーを使用して、UI Automationをサポートします。 規則により、ピア クラスの名前はコントロール クラスの名前で始まり "AutomationPeer" で終わります。 たとえば、ButtonAutomationPeerButton コントロール クラスのピア クラスです。 ピア クラスは、UI Automation コントロール型とほぼ同等ですが、WPF 要素に固有のものです。 UI Automation インターフェイスを使用して WPF アプリケーションにアクセスするオートメーション コードはオートメーション ピアを直接には使用しませんが、同じプロセス空間内のオートメーション コードはオートメーション ピアを直接使用できます。

組み込みのオートメーション ピア クラス

要素がユーザーによるインターフェイス アクティビティを受け入れる場合、または要素にスクリーンリーダー アプリケーションのユーザーが必要とする情報が含まれている場合、それらの要素はオートメーション ピア クラスを実装します。 WPF のすべてのビジュアル要素がオートメーション ピアを持つわけではありません。 オートメーション ピアを実装するクラスの例としては、ButtonTextBox、および Label があります。 オートメーション ピアを実装しないクラスの例としては、Decorator から派生するクラス (Border など)、および Panel に基づくクラス (GridCanvas など) があります。

Control 基本クラスには、対応するピア クラスはありません。 Control から派生するカスタム コントロールのピア クラスが必要な場合は、FrameworkElementAutomationPeer からカスタム ピア クラスを派生させる必要があります。

派生ピアのセキュリティに関する考慮事項

オートメーション ピアは、部分信頼環境で実行する必要があります。 UIAutomationClient アセンブリ内のコードは部分信頼環境で実行されるように構成されておらず、オートメーション ピア コードはこのアセンブリを参照しないようにする必要があります。 その代わりに、UIAutomationTypes アセンブリ内のクラスを使用します。 たとえば、UIAutomationTypes アセンブリ内の AutomationElementIdentifiers クラスを使用します。このクラスは、UIAutomationClient アセンブリ内の AutomationElement クラスに対応します。 オートメーション ピア コードで UIAutomationTypes アセンブリを参照しても問題ありません。

ピアのナビゲーション

オートメーション ピアが見つかると、インプロセス コードはオブジェクトの GetChildren メソッドと GetParent メソッドを呼び出して、ピア ツリーをナビゲーションすることができます。 コントロール内の WPF 要素間のナビゲーションは、ピアの GetChildrenCore メソッドの実装によってサポートされます。 UI オートメーション システムは、このメソッドを呼び出して、コントロール内のサブ要素 (リスト ボックス内のリスト項目など) のツリーを作成します。 既定の UIElementAutomationPeer.GetChildrenCore メソッドは、要素のビジュアル ツリーを移動して、オートメーション ピアのツリーを作成します。 カスタム コントロールはこのメソッドをオーバーライドして子要素をオートメーション クライアントに公開し、情報を伝達する要素やユーザー操作を許可する要素のオートメーション ピアを返します。

派生ピアでのカスタマイズ

UIElement および ContentElement から派生するすべてのクラスには、プロテクト仮想メソッド OnCreateAutomationPeer が含まれています。 WPF は OnCreateAutomationPeer を呼び出して、各コントロールのオートメーション ピア オブジェクトを取得します。 オートメーション コードはピアを使用して、コントロールの特性と機能に関する情報を取得したり、対話型の使用をシミュレーションしたりすることができます。 オートメーションをサポートするカスタム コントロールは、OnCreateAutomationPeer をオーバーライドし、AutomationPeer から派生するクラスのインスタンスを返す必要があります。 たとえば、ButtonBase クラスから派生するカスタム コントロールの場合、OnCreateAutomationPeer で返されるオブジェクトは ButtonBaseAutomationPeer から派生したものであることが必要です。

カスタム コントロールを実装するときには、そのカスタム コントロールに固有な一意の動作を表す、基本オートメーション ピア クラスの "Core" メソッドをオーバーライドする必要があります。

OnCreateAutomationPeer のオーバーライド

カスタム コントロールの OnCreateAutomationPeer メソッドをオーバーライドして、AutomationPeer から直接的または間接的に派生するプロバイダー オブジェクトを返すようにします。

GetPattern のオーバーライド

オートメーション ピアによって、サーバー側 UI Automation プロバイダーの実装の一部が簡略化されますが、カスタム コントロール オートメーション ピアでパターン インターフェイスを処理する必要性は変わりません。 ピアは、非 WPF プロバイダーと同様に、System.Windows.Automation.Provider 名前空間内のインターフェイス (IInvokeProvider など) の実装を提供することによってコントロール パターンをサポートします。 コントロール パターン インターフェイスは、ピア自体または別のオブジェクトによって実装できます。 ピアの GetPattern の実装は、指定されたパターンをサポートするオブジェクトを返します。 UI Automation コードは、GetPattern メソッドを呼び出し、PatternInterface 列挙値を指定します。 GetPattern のオーバーライドでは、指定されたパターンを実装するオブジェクトが返される必要があります。 パターンのカスタム実装がコントロールに含まれていない場合、基本型の GetPattern の実装を呼び出すことで、その実装、または null (このコントロール型でパターンがサポートされていない場合) を取得できます。 たとえば、カスタムの NumericUpDown コントロールを範囲内の値に設定して、その UI Automation ピアが IRangeValueProvider インターフェイスを実装するようにすることができます。 次の例は、ピアの GetPattern メソッドを PatternInterface.RangeValue 値に応答するようにオーバーライドする方法を示しています。

        Public Overrides Function GetPattern(ByVal patternInterface As PatternInterface) As Object
            If patternInterface = PatternInterface.RangeValue Then
                Return Me
            End If
            Return MyBase.GetPattern(patternInterface)
        End Function
public override object GetPattern(PatternInterface patternInterface)
{
    if (patternInterface == PatternInterface.RangeValue)
    {
        return this;
    }
    return base.GetPattern(patternInterface);
}

GetPattern メソッドでは、サブ要素をパターン プロバイダーとして指定することもできます。 次のコードは、ItemsControl がその内部 ScrollViewer コントロールのピアにスクロール パターン処理を転送する方法を示しています。

public override object GetPattern(PatternInterface patternInterface)
{
    if (patternInterface == PatternInterface.Scroll)
    {
        ItemsControl owner = (ItemsControl) base.Owner;

        // ScrollHost is internal to the ItemsControl class
        if (owner.ScrollHost != null)
        {
            AutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(owner.ScrollHost);
            if ((peer != null) && (peer is IScrollProvider))
            {
                peer.EventsSource = this;
                return (IScrollProvider) peer;
            }
        }
    }
    return base.GetPattern(patternInterface);
}
Public Class Class1
    Public Overrides Function GetPattern(ByVal patternInterface__1 As PatternInterface) As Object
        If patternInterface1 = PatternInterface.Scroll Then
            Dim owner As ItemsControl = DirectCast(MyBase.Owner, ItemsControl)

            ' ScrollHost is internal to the ItemsControl class
            If owner.ScrollHost IsNot Nothing Then
                Dim peer As AutomationPeer = UIElementAutomationPeer.CreatePeerForElement(owner.ScrollHost)
                If (peer IsNot Nothing) AndAlso (TypeOf peer Is IScrollProvider) Then
                    peer.EventsSource = Me
                    Return DirectCast(peer, IScrollProvider)
                End If
            End If
        End If
        Return MyBase.GetPattern(patternInterface1)
    End Function
End Class

パターン処理用にサブ要素を指定するため、このコードはサブ要素オブジェクトを取得し、CreatePeerForElement メソッドを使用してピアを作成し、新しいピアの EventsSource プロパティを現在のピアに設定し、新しいピアを返します。 サブ要素に EventsSource を設定すると、そのサブ要素はオートメーション ピア ツリーに表示されず、そのサブ要素が発生させるすべてのイベントは EventsSource で指定したコントロールから生成されたものとして扱われます。 ScrollViewer コントロールはオートメーション ツリーに表示されず、それが生成するスクロール イベントは ItemsControl オブジェクトから生成されたものとして表示されます。

"Core" メソッドのオーバーライド

オートメーション コードは、ピア クラスのパブリック メソッドを呼び出して、コントロールに関する情報を取得します。 コントロールに関する情報を提供するためには、コントロールの実装が基本オートメーション ピア クラスが提供する実装と異なる場合に、"Core" で終わる各メソッドをオーバーライドします。 次の例で示すように、コントロールが少なくとも GetClassNameCore メソッドと GetAutomationControlTypeCore メソッドを実装している必要があります。

        Protected Overrides Function GetClassNameCore() As String
            Return "NumericUpDown"
        End Function

        Protected Overrides Function GetAutomationControlTypeCore() As AutomationControlType
            Return AutomationControlType.Spinner
        End Function
protected override string GetClassNameCore()
{
    return "NumericUpDown";
}

protected override AutomationControlType GetAutomationControlTypeCore()
{
    return AutomationControlType.Spinner;
}

GetAutomationControlTypeCore の実装は、ControlType 値を返すことによって、コントロールを表します。 ControlType.Custom を返すことはできますが、コントロールを正確に表す場合は、より限定的なコントロール型のいずれかを返す必要があります。 ControlType.Custom の戻り値では、プロバイダーが UI Automationを実装するのに余分な作業が必要となり、UI Automationのクライアント製品は、制御構造、キーボード操作、およびコントロール パターンを予測できません。

コントロールにデータ コンテンツが含まれるか、コントロールがユーザー インターフェイスで対話的な役割を果たすか、またはその両方であることを示すには、IsContentElementCore メソッドと IsControlElementCore メソッドを実装します。 既定では、両方のメソッドが true を返します。 これらの設定によって、オートメーション ツリーのフィルター処理にこれらを使用する、スクリーン リーダーなどのオートメーション ツールの操作性が向上します。 GetPattern メソッドがパターン処理をサブ要素のピアに転送する場合、サブ要素のピアの IsControlElementCore メソッドは、false を返してオートメーション ツリーにサブ要素のピアが表示されないようにすることができます。 たとえば、ListBox でのスクロールは ScrollViewer によって処理され、PatternInterface.Scroll のオートメーション ピアは、ListBoxAutomationPeer と関連付けられている ScrollViewerAutomationPeerGetPattern メソッドから返されます。このため ScrollViewerAutomationPeerIsControlElementCore メソッドは false を返し、ScrollViewerAutomationPeer はオートメーション ツリーに表示されません。

オートメーション ピアは、コントロール用に適切な既定値を提供する必要があります。 コントロールを参照する XAML は、AutomationProperties 属性を含めることによって、"Core" メソッドのピア実装をオーバーライドできます。 たとえば、次の XAML では、2 つのカスタマイズされた UI Automation プロパティを持つボタンを作成します。

<Button AutomationProperties.Name="Special" 
    AutomationProperties.HelpText="This is a special button."/>

パターン プロバイダーの実装

所有する要素が Control から直接派生する場合は、カスタム プロバイダーによって実装されたインターフェイスを明示的に宣言します。 たとえば、次のコードでは、範囲値を実装する Control のピアを宣言しています。

public class RangePeer1 : FrameworkElementAutomationPeer, IRangeValueProvider { }
Public Class RangePeer1
    Inherits FrameworkElementAutomationPeer
    Implements IRangeValueProvider
End Class

所有するコントロールが特定のコントロール型 (RangeBase など) から派生する場合は、それと等価な派生ピア クラスからピアを派生させることができます。 この場合は、IRangeValueProvider の基本実装を提供する RangeBaseAutomationPeer からピアを派生させます。 次のコードでは、こうしたピアを宣言しています。

public class RangePeer2 : RangeBaseAutomationPeer { }
Public Class RangePeer2
    Inherits RangeBaseAutomationPeer
End Class

実装例については、テーマおよび UI オートメーションがサポートされた NumericUpDown カスタム コントロールのサンプルを参照してください。

イベントの発生

オートメーション クライアントはオートメーション イベントをサブスクライブできます。 カスタム コントロールは、RaiseAutomationEvent メソッドを呼び出して、コントロールの状態に対する変更を報告する必要があります。 同様に、プロパティ値が変更された場合は、RaisePropertyChangedEvent メソッドを呼び出します。 次のコードは、コントロール コード内からピア オブジェクトを取得し、イベントを発生させるメソッドを呼び出す方法を示しています。 最適化の手法として、このコードはこの種類のイベントのリスナーが存在するかどうかを判断します。 リスナーが存在する場合にだけイベントを発生させることによって、不要なオーバーヘッドを回避し、コントロールの応答性の維持に役立てます。

            If AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged) Then
                Dim peer As NumericUpDownAutomationPeer = TryCast(UIElementAutomationPeer.FromElement(nudCtrl), NumericUpDownAutomationPeer)

                If peer IsNot Nothing Then
                    peer.RaisePropertyChangedEvent(RangeValuePatternIdentifiers.ValueProperty, CDbl(oldValue), CDbl(newValue))
                End If
            End If
if (AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged))
{
    NumericUpDownAutomationPeer peer = 
        UIElementAutomationPeer.FromElement(nudCtrl) as NumericUpDownAutomationPeer;

    if (peer != null)
    {
        peer.RaisePropertyChangedEvent(
            RangeValuePatternIdentifiers.ValueProperty,
            (double)oldValue,
            (double)newValue);
    }
}

参照

概念

UI オートメーションの概要

サーバー側 UI オートメーション プロバイダーの実装

その他の技術情報

テーマおよび UI オートメーションがサポートされた NumericUpDown カスタム コントロールのサンプル

履歴の変更

日付

履歴

理由

2010 年 12 月

Visual Basic の例を補足。

コンテンツ バグ修正

2008 年 7 月

トピックを追加

情報の拡充