Partager via


Utiliser la propriété AutomationID

RemarqueRemarque

Cette documentation s'adresse aux développeurs .NET Framework qui veulent utiliser les classes UI Automation managées définies dans l'espace de noms System.Windows.Automation.Pour obtenir les informations les plus récentes sur UI Automation, consultez API Windows Automation : UI Automation (page éventuellement en anglais).

Cette rubrique contient des scénarios et un exemple de code qui indiquent quand et comment AutomationIdProperty peut être utilisé pour localiser un élément dans l'arborescence UI Automation.

AutomationIdProperty identifie de manière unique un élément UI Automation de ses frères. Pour plus d'informations sur les identificateurs de propriété associés à une identification du contrôle, consultez Vue d'ensemble des propriétés UI Automation.

RemarqueRemarque

AutomationIdProperty ne garantit pas une identité unique dans toute l'arborescence ; en général, pour être utile, elle a besoin d'un conteneur et d'informations de portée.Par exemple, une application peut contenir un contrôle de menu avec plusieurs éléments de menu de niveau supérieur qui, eux-mêmes, contiennent plusieurs éléments de menu enfants.Ces éléments de menu secondaires peuvent être identifiés par un schéma générique tel que « Item1 », « Item 2 », etc., qui autorise les identificateurs dupliqués pour les enfants dans les éléments de menu de niveau supérieur.

Scénarios

Trois scénarios d'application de client UI Automation principaux ont été identifiés et requièrent l'utilisation de AutomationIdProperty pour obtenir des résultats exacts et cohérents lors de la recherche d'éléments.

RemarqueRemarque

AutomationIdProperty est pris en charge par tous les éléments UI Automation de l'affichage de contrôle, sauf par les fenêtres d'application de niveau supérieur, par les éléments UI Automation dérivés de contrôles Windows Presentation Foundation (WPF) qui n'ont pas d'ID ou de x:Uid et par les éléments UI Automation dérivés des contrôles Win32 qui n'ont pas d'ID de contrôle.

Utilisation d'un AutomationID unique et détectable pour localiser un élément spécifique de l'arborescence UI Automation

  • Utilisez un outil tel que UI Spy pour signaler le AutomationIdProperty d'un élément d'UI intéressant. Cette valeur peut ensuite être copiée et collée dans une application cliente telle qu'un script de test pour un prochain test automatisé. Cette approche réduit et simplifie le code nécessaire pour identifier et localiser un élément pendant l'exécution.
Remarque AttentionAttention

En général, vous devez essayer de n'obtenir que les enfants directs du RootElement.Une recherche des descendants peut itérer au sein de centaines ou de milliers d'éléments, ce qui peut provoquer un dépassement de capacité de la pile.Si vous tentez d'obtenir un élément spécifique à un niveau inférieur, vous devez commencer votre recherche à partir de la fenêtre d'application ou d'un conteneur à un niveau inférieur.

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

Utilisation d'un chemin d'accès persistant pour retourner à un AutomationElement identifié précédemment

  • Les applications clientes, des simples scripts de test aux utilitaires d'enregistrement et de lecture fiables, peuvent nécessiter un accès aux éléments qui ne sont pas encore instanciés, tels qu'une boîte de dialogue d'ouverture de fichier ou un élément de menu ; par conséquent, elles n'existent pas dans l'arborescence UI Automation. Ces éléments ne peuvent être instanciés qu'en reproduisant, ou en « rejouant », une séquence spécifique d'actions de l'user interface (UI) via l'utilisation de propriétés UI Automation telles que les AutomationID, les modèles de contrôle et les écouteurs d'événements. Pour obtenir un exemple qui utilise Microsoft UI Automation pour générer des scripts de test basés sur l'interaction de l'utilisateur avec l'user interface (UI), consultez Test Script Generator Sample.
        '''--------------------------------------------------------------------
        ''' <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);
}

Utilisation d'un chemin d'accès relatif pour retourner à un AutomationElement identifié précédemment

  • Dans certaines circonstances, étant donné que AutomationID n'est considéré comme unique que parmi ses frères, de nombreux éléments de l'arborescence UI Automation peuvent avoir des valeurs de propriété AutomationID identiques. Dans ces situations, les éléments peuvent être identifiés de façon unique en se basant sur un parent et, si nécessaire, un grand-parent. Par exemple, un développeur peut fournir une barre de menus avec plusieurs éléments de menu, chacun avec plusieurs éléments de menu enfants où les enfants sont identifiés avec un AutomationID séquentiel tel que « Item1 », « Item2 », etc. Chaque élément de menu pourrait ensuite être identifié de manière unique par son AutomationID avec l'AutomationID de son parent et, si nécessaire, de son grand-parent.

Voir aussi

Tâches

Rechercher un élément UI Automation basé sur une condition de propriété

Référence

AutomationIdProperty

Concepts

Vue d'ensemble de l'arborescence UI Automation