AutomationID プロパティの使用

メモメモ

このドキュメントは、System.Windows.Automation 名前空間で定義されているマネージ UI Automation クラスを使用する .NET Framework 開発者を対象としています。UI Automationに関する最新情報については、「Windows Automation API: UI Automation (Windows オートメーション API: UI オートメーション)」を参照してください。

ここでは、AutomationIdProperty を使用してUI Automation ツリー内の要素を検索する方法とタイミングを説明するシナリオとサンプル コードを示します。

AutomationIdProperty は、UI オートメーション要素をその兄弟から一意に識別します。 コントロールの識別に関連するプロパティ識別子の詳細については、「UI オートメーション プロパティの概要」を参照してください。

メモメモ

AutomationIdProperty は、ツリー全体の中で一意に識別できることを保証されていません。通常は、コンテナーおよびスコープ情報と組み合わせて使用する必要があります。たとえば、アプリケーションには複数のトップレベルのメニュー項目を持つメニュー コントロールが含まれ、さらに、それらのメニュー項目に複数の子メニュー項目が含まれている場合があります。これらの 2 次メニュー項目は、"Item1"、"Item2" などの汎用スキームで識別され、トップレベルのメニュー項目間で子の識別子が重複することがあります。

シナリオ

以下に示す UI オートメーション クライアント アプリケーションのシナリオは、要素の検索時に正確で一貫性のある結果を得るために AutomationIdProperty を使用する必要がある 3 つの主なケースです。

メモメモ

AutomationIdProperty は、トップレベルのアプリケーション ウィンドウ、ID または x:Uid を持たない Windows Presentation Foundation (WPF) コントロールから派生した UI オートメーション要素、コントロール ID を持たない Win32 コントロールから派生した UI オートメーション要素を除く、コントロール ビュー内のすべての UI オートメーション要素によってサポートされます。

検出可能な一意の AutomationID を使用して UI オートメーション ツリー内の特定の要素を検索

  • UI Spy などのツールを使用して、対象の UI 要素の AutomationIdProperty を報告します。 この値をコピーし、後続の自動テストを行うためのテスト スクリプトなど、クライアント アプリケーションに貼り付けることができます。 この方法を使用すると、実行時に要素を特定および検索するために必要なコードを削減し、簡素化できます。
Caution メモ注意

一般に、RootElement の直接の子だけを取得する必要があります。子孫を検索すると、要素の処理が数百回または数千回も繰り返される場合があるため、スタック オーバーフローが発生する可能性があります。低いレベルにある特定の要素を取得する場合は、アプリケーション ウィンドウまたは低いレベルのコンテナーから検索を開始する必要があります。

'''--------------------------------------------------------------------
''' <summary>
''' Finds all elements in the UI Automation tree that have a specified
''' AutomationID.
''' </summary>
''' <param name="targetApp">
''' The root element from which to start searching.
''' </param>
''' <param name="automationID">
''' The AutomationID value of interest.
''' </param>
''' <returns>
''' The collection of automation elements that have the specified 
''' AutomationID value.
''' </returns>
'''--------------------------------------------------------------------
Private Function FindElementFromAutomationID( _
ByVal targetApp As AutomationElement, _
ByVal automationID As String) As AutomationElementCollection
    Return targetApp.FindAll( _
    TreeScope.Descendants, _
    New PropertyCondition( _
    AutomationElement.AutomationIdProperty, automationID))
End Function 'FindElementFromAutomationID
///--------------------------------------------------------------------
/// <summary>
/// Finds all elements in the UI Automation tree that have a specified
/// AutomationID.
/// </summary>
/// <param name="targetApp">
/// The root element from which to start searching.
/// </param>
/// <param name="automationID">
/// The AutomationID value of interest.
/// </param>
/// <returns>
/// The collection of UI Automation elements that have the specified 
/// AutomationID value.
/// </returns>
///--------------------------------------------------------------------
private AutomationElementCollection FindElementFromAutomationID(AutomationElement targetApp, 
    string automationID)
{
    return targetApp.FindAll(
        TreeScope.Descendants,
        new PropertyCondition(AutomationElement.AutomationIdProperty, automationID));
}

以前に識別された AutomationElement に戻るために固定パスを使用

  • 単純なテスト スクリプトから堅牢なレコードおよび再生ユーティリティまで、さまざまなクライアント アプリケーションにおいて、現在はインスタンス化されていないために UI オートメーション ツリー内には存在しない要素へのアクセスが必要になる場合があります。たとえば、[ファイルを開く] ダイアログ ボックスやメニュー項目へのアクセスが必要な場合です。 これらの要素は、AutomationID、コントロール パターン、イベント リスナーなどの UI Automation プロパティを使用して特定の一連の user interface (UI) アクションを再生することでのみインスタンス化できます。 Microsoft UI Automationを使用して、ユーザーとuser interface (UI) との対話に基づくテスト スクリプトを生成する例については、「テスト スクリプト ジェネレーターのサンプル」を参照してください。
        '''--------------------------------------------------------------------
        ''' <summary>
        ''' Creates a UI Automation thread.
        ''' </summary>
        ''' <param name="sender">Object that raised the event.</param>
        ''' <param name="e">Event arguments.</param>
        ''' <remarks>
        ''' UI Automation must be called on a separate thread if the client 
        ''' application itself could become a target for event handling.
        ''' For example, focus tracking is a desktop event that could involve
        ''' the client application.
        ''' </remarks>
        '''--------------------------------------------------------------------
        Private Sub CreateUIAThread(ByVal sender As Object, ByVal e As EventArgs)

            ' Start another thread to do the UI Automation work.
            Dim threadDelegate As New ThreadStart(AddressOf CreateUIAWorker)
            Dim workerThread As New Thread(threadDelegate)
            workerThread.Start()

        End Sub 'CreateUIAThread


        '''--------------------------------------------------------------------
        ''' <summary>
        ''' Delegated method for ThreadStart. Creates a UI Automation worker 
        ''' class that does all UI Automation related work.
        ''' </summary>
        '''--------------------------------------------------------------------
        Public Sub CreateUIAWorker()

            uiautoWorker = New UIAWorker(targetApp)

        End Sub 'CreateUIAWorker

        Private uiautoWorker As UIAWorker



...


'''--------------------------------------------------------------------
''' <summary>
''' Function to playback through a series of recorded events calling
''' a WriteToScript function for each event of interest.
''' </summary>
''' <remarks>
''' A major drawback to using AutomationID for recording user 
''' interactions in a volatile UI is the probability of catastrophic 
''' change in the UI. For example, the 'Processes' dialog where items 
''' in the listbox container can change with no input from the user.
''' This mandates thtat a record and playback application must be 
''' reliant on the tester owning the UI being tested. In other words, 
''' there has to be a contract between the provider and client that 
''' excludes uncontrolled, external applications. The added benefit 
''' is the guarantee that each control in the UI should have an
''' AutomationID assigned to it.
''' 
''' This function relies on a UI Automation worker class to create
''' the System.Collections.Generic.Queue object that stores the 
''' information for the recorded user interactions. This
''' allows post-processing of the recorded items prior to actually
''' writing them to a script. If this is not necessary the interaction 
''' could be written to the script immediately.
''' </remarks>
'''--------------------------------------------------------------------
Private Sub Playback(ByVal targetApp As AutomationElement)

    Dim element As AutomationElement
    Dim storedItem As ElementStore
    For Each storedItem In uiautoWorker.elementQueue
        Dim propertyCondition As New PropertyCondition( _
        AutomationElement.AutomationIdProperty, storedItem.AutomationID)
        ' Confirm the existence of a control.
        ' Depending on the controls and complexity of interaction
        ' this step may not be necessary or may require additional 
        ' functionality. For example, to confirm the existence of a 
        ' child menu item that had been invoked the parent menu item 
        ' would have to be expanded. 
        element = targetApp.FindFirst( _
        TreeScope.Descendants, propertyCondition)
        If element Is Nothing Then
            ' Control not available, unable to continue.
            ' TODO: Handle error condition.
            Return
        End If
        WriteToScript(storedItem.AutomationID, storedItem.EventID)
    Next storedItem

End Sub 'Playback


'''--------------------------------------------------------------------
''' <summary>
''' Generates script code and outputs the code to a text control in 
''' the client.
''' </summary>
''' <param name="automationID">
''' The AutomationID of the current control.
''' </param>
''' <param name="eventID">
''' The event recorded on that control.
''' </param>
'''--------------------------------------------------------------------
Private Sub WriteToScript( _
ByVal automationID As String, ByVal eventID As String)

    ' Script code would be generated and written to an output file
    ' as plain text at this point, but for the
    ' purposes of this example we just write to the console.
    Console.WriteLine(automationID + " - " + eventID)

End Sub 'WriteToScript
        ///--------------------------------------------------------------------
        /// <summary>
        /// Creates a UI Automation thread.
        /// </summary>
        /// <param name="sender">Object that raised the event.</param>
        /// <param name="e">Event arguments.</param>
        /// <remarks>
        /// UI Automation must be called on a separate thread if the client 
        /// application itself could become a target for event handling.
        /// For example, focus tracking is a desktop event that could involve
        /// the client application.
        /// </remarks>
        ///--------------------------------------------------------------------
        private void CreateUIAThread(object sender, EventArgs e)
        {
            // Start another thread to do the UI Automation work.
            ThreadStart threadDelegate = new ThreadStart(CreateUIAWorker);
            Thread workerThread = new Thread(threadDelegate);
            workerThread.Start();
        }

        ///--------------------------------------------------------------------
        /// <summary>
        /// Delegated method for ThreadStart. Creates a UI Automation worker 
        /// class that does all UI Automation related work.
        /// </summary>
        ///--------------------------------------------------------------------
        public void CreateUIAWorker()
        {
           uiautoWorker = new FindByAutomationID(targetApp);
        }
        private FindByAutomationID uiautoWorker;



...


///--------------------------------------------------------------------
/// <summary>
/// Function to playback through a series of recorded events calling
/// a WriteToScript function for each event of interest.
/// </summary>
/// <remarks>
/// A major drawback to using AutomationID for recording user 
/// interactions in a volatile UI is the probability of catastrophic 
/// change in the UI. For example, the //Processes// dialog where items 
/// in the listbox container can change with no input from the user.
/// This mandates thtat a record and playback application must be 
/// reliant on the tester owning the UI being tested. In other words, 
/// there has to be a contract between the provider and client that 
/// excludes uncontrolled, external applications. The added benefit 
/// is the guarantee that each control in the UI should have an
/// AutomationID assigned to it.
/// 
/// This function relies on a UI Automation worker class to create
/// the System.Collections.Generic.Queue object that stores the 
/// information for the recorded user interactions. This
/// allows post-processing of the recorded items prior to actually
/// writing them to a script. If this is not necessary the interaction 
/// could be written to the script immediately.
/// </remarks>
///--------------------------------------------------------------------
private void Playback(AutomationElement targetApp)
{
    AutomationElement element; 
    foreach(ElementStore storedItem in uiautoWorker.elementQueue)
    {
        PropertyCondition propertyCondition = 
            new PropertyCondition(
            AutomationElement.AutomationIdProperty, storedItem.AutomationID);
        // Confirm the existence of a control.
        // Depending on the controls and complexity of interaction
        // this step may not be necessary or may require additional 
        // functionality. For example, to confirm the existence of a 
        // child menu item that had been invoked the parent menu item 
        // would have to be expanded. 
        element = targetApp.FindFirst(TreeScope.Descendants, propertyCondition);
        if(element == null)
        {
            // Control not available, unable to continue.
            // TODO: Handle error condition.
            return;
        }
        WriteToScript(storedItem.AutomationID, storedItem.EventID);
    }
}

///--------------------------------------------------------------------
/// <summary>
/// Generates script code and outputs the code to a text control in 
/// the client.
/// </summary>
/// <param name="automationID">
/// The AutomationID of the current control.
/// </param>
/// <param name="eventID">
/// The event recorded on that control.
/// </param>
///--------------------------------------------------------------------
private void WriteToScript(string automationID, string eventID)
{
    // Script code would be generated and written to an output file
    // as plain text at this point, but for the
    // purposes of this example we just write to the console.
    Console.WriteLine(automationID + " - " + eventID);
}

以前に識別された AutomationElement に戻るために相対パスを使用

  • AutomationID は兄弟の間でのみ一意であることがあるため、UI オートメーション ツリー内の複数の要素が同じ AutomationID プロパティ値を持つ場合があります。 このような場合に要素を一意に識別するには、親、および必要に応じて祖父母を使用します。 たとえば、複数のメニュー項目を持つメニュー バーを作成し、各メニュー項目に複数の子メニュー項目がある場合に、その子メニュー項目が "Item1"、"Item2" などの連続する AutomationID で識別されるとします。 このとき、各メニュー項目は、その AutomationID に加えて、その親、および必要に応じてその祖父母の AutomationID で一意に識別できます。

参照

処理手順

プロパティ条件に基づく UI オートメーション要素の検索

参照

AutomationIdProperty

概念

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