Freigeben über


Verwenden der AutomationID-Eigenschaft

HinweisHinweis

Diese Dokumentation ist für .NET Framework-Entwickler vorgesehen, die die verwalteten UI Automation-Klassen verwenden möchten, die im System.Windows.Automation-Namespace definiert sind.Aktuelle Informationen zu UI Automation finden Sie unter Windows Automation API: UI Automation.

Dieses Thema enthält Szenarien und Codebeispiele zum Veranschaulichen, wie und wann Sie die AutomationIdProperty verwenden können, um ein Element in der UI Automation-Struktur zu suchen.

Anhand der AutomationIdProperty unterscheidet sich ein Benutzeroberflächenautomatisierungs-Element eindeutig von seinen nebengeordneten Elementen. Weitere Informationen zu Eigenschaftenbezeichnern, die zur Identifikation von Steuerelementen dienen, finden Sie unter Übersicht über die Benutzeroberflächenautomatisierungs-Eigenschaften.

HinweisHinweis

Durch AutomationIdProperty wird keine in der gesamten Struktur garantiert eindeutige Identität zur Verfügung gestellt. Diese Eigenschaft kann normalerweise erst durch weitere Informationen zum Container und Bereich sinnvoll verwendet werden.Eine Anwendung kann beispielsweise ein Menüsteuerelement mit mehreren Menüeinträgen oberster Ebene enthalten, die wiederum mehrere untergeordnete Menüeinträge aufweisen.Diese sekundären Menüeinträge können durch ein allgemeines Schema wie "Element1", "Element2", "Element3" usw. identifiziert werden. Dadurch sind für die untergeordneten Elemente der Menüeinträge oberster Ebene doppelte Bezeichner möglich.

Szenarien

Es wurden drei primäre Anwendungsszenarien für Benutzeroberflächenautomatisierungs-Client-Anwendungen identifiziert, in denen AutomationIdProperty verwendet werden muss, um beim Suchen nach Elementen richtige und konsistente Ergebnisse zu liefern.

HinweisHinweis

AutomationIdProperty wird von allen Benutzeroberflächenautomatisierungs-Elementen in der Steuerelementansicht unterstützt, mit Ausnahme von Anwendungsfenstern der obersten Ebene, Benutzeroberflächenautomatisierungs-Elementen, die von Windows Presentation Foundation (WPF)-Steuerelementen ohne ID oder x:Uid abgeleitet wurden, und von Win32-Steuerelementen abgeleiteten Benutzeroberflächenautomatisierungs-Elementen, die nicht über eine Steuerelement-ID verfügen.

Suchen eines bestimmten Elements in der Benutzeroberflächenautomatisierungs-Struktur anhand einer eindeutigen und erkennbaren AutomationID

  • Verwenden Sie ein Tool wie UI Spy, um die AutomationIdProperty eines relevanten UI-Elements zu ermitteln. Anschließend können Sie diesen Wert kopieren und in einer Clientanwendung (z. B. einem Testskript für spätere automatisierte Tests) einfügen. Durch diesen Ansatz wird der Code, der erforderlich ist, um ein Element zur Laufzeit zu identifizieren und zu suchen, weniger umfangreich und einfacher.
WarnhinweisVorsicht

Im Allgemeinen sollten Sie nur direkt untergeordnete Elemente vom RootElement abrufen.Eine Suche nach Nachfolgerelementen kann hunderte oder sogar tausende Elemente durchlaufen und möglicherweise einen Stapelüberlauf verursachen.Wenn ein bestimmtes Element auf einer niedrigeren Ebene abgerufen werden soll, sollten Sie die Suche im Anwendungsfenster oder in einem Container auf niedrigerer Ebene starten.

'''--------------------------------------------------------------------
''' <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));
}

Verwenden eines persistenten Pfads zum Zurückkehren zu einem vorher identifizierten AutomationElement

  • Möglicherweise müssen Clientanwendungen (von einfachen Testskripts bis zu robusten Aufzeichnungs- und Wiedergabeprogrammen) auf Elemente (z. B. ein Dialogfeld zum Öffnen von Dateien oder ein Menüelement) zugreifen, die zurzeit nicht instanziiert und deshalb in der Benutzeroberflächenautomatisierungs-Struktur nicht vorhanden sind. Diese Elemente können nur instanziiert werden, indem unter Verwendung von user interface (UI)-Eigenschaften (wie AutomationID), Steuerelementmustern und Ereignislistenern eine bestimmte Folge von UI Automation-Aktionen reproduziert (oder "wiedergegeben") wird. Unter Test Script Generator Sample finden Sie ein Beispiel, das Microsoft UI Automation verwendet, um auf Grundlage der Benutzerinteraktion mit der user interface (UI) Testskripts zu generieren.
        '''--------------------------------------------------------------------
        ''' <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);
}

Verwenden eines relativen Pfads zum Zurückkehren zu einem vorher identifizierten AutomationElement

  • Da AutomationID nur bei nebengeordneten Elementen garantiert eindeutig ist, haben unter bestimmten Umständen möglicherweise mehrere Elemente in der Benutzeroberflächenautomatisierungs-Struktur identische AutomationID-Eigenschaftswerte. In diesen Fällen können die Elemente anhand ihres übergeordneten Elements und bei Bedarf dessen übergeordneten Elements eindeutig identifiziert werden. Beispielsweise stellt ein Entwickler möglicherweise eine Menüleiste mit mehreren Menüelementen bereit, die jeweils über mehrere untergeordnete Menüelemente verfügen. Die untergeordneten Elemente werden dabei mit sequenziellen AutomationIDs wie "Element1", "Element2" usw. identifiziert. Jedes Menüelement kann dann anhand der eigenen AutomationID sowie der des übergeordneten Elements und bei Bedarf der eines weiteren übergeordneten Elements eindeutig identifiziert werden.

Siehe auch

Aufgaben

Suchen eines Benutzeroberflächenautomatisierungs-Elements anhand einer Eigenschaftenbedingung

Referenz

AutomationIdProperty

Konzepte

Übersicht über die Benutzeroberflächenautomatisierungs-Struktur