Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Thomas Lebrun

Tout sur WPF, LINQ, C# et .NET en général !

Actualités

[WPF] WPF & UI Automation: Rendez vos interfaces graphiques accessibles !

Avec l'arrivée du framework .NET 3.0, on a vu pas mal de nouveautés (WPF, WF, WCF, CardSpace). Mais il y a un autre domaine où les choses ont pas mal bougées: l'accessibilité Smile

Il s'agit d'un domaine intéressant mais qui est, malheureusement, souvent mis de coté par les développeurs car cela ne fait pas partit des spécifications du programme, ils n'ont pas envie, etc....

Microsoft "UI Automation" (User Interface Automation) est le nouveau framework d'accessibilité pour Microsoft Windows, disponible pour tous les système d'exploitation qui supporte Windows Presentation Foundation (WPF).

 

 

Qu'est-ce-que l'UI Automation ?

Pour faire court, sachez qu'il s'agit d'un accès (par programmation) à la plupart des éléments de l'interface utilisateur.

 

Pourquoi est-ce important ?

Tout simplement car c'est comme cela que les applications de type "lecteur d'écran" (Screen Readers) peuvent fonctionner. Les applications de type Screen Readers sont souvent utilisées par les personnes mal-voyantes, afin de pouvoir manipuler votre application autrement que par l'utilisation des moyens habituels (souris en particulier).

 

UI Automation: Fournisseur et Client:

L'UI Automation se divise en 2 branches. D'un coté, vous avez ce que l'on appelle les fournisseurs ("UI Automation Providers"). Il s'agit tout simplement des applications existantes (notepad, Word, etc....) ou que vous développez et qui pourraient-être utilisées par des utilisateurs nécessitant une aide, en terme d'accessibilité.

De l'autre, vous avez les clients ("UI Automation Clients") qui sont tous simplement les applications type Screen Reader: bref, les applications qui utilisent ce que propose un fournisseur pour améliorer l'accessibilité. Dans cette catégorie, on met généralement les scripts d'automatisation qui sont utilisés pour tout ce qui concerne le test automatique de l'interface utilisateur (tests de stress, etc...)

 

Comment ca marche ?

Si vous développez une application WPF, et bien vous n'avez pas grand chose à faire Smile

Pour être fournisseur:

Si vous souhaitez que votre application soit fournisseur (autrement dit qu'elle puisse être utilisée correctement par un Screen Reader ou autre), sachez que cela est géré nativement. Les références adéquates ont été ajoutées dès la création du projet:

uiautomation

Et il ne vous reste plus qu'à spécifier les AutomationProperties qui vous intéresse:

automation

A partir de là, l'application en charge d'améliorer l'accessibilité se contentera d'utiliser les informations dont elle aura besoin.

Pour être client:

Si vous avez par exemple besoin de développer un script d'automatisation d'interface utilisateur, la démarche est un peu plus compliquée (mais pas trop quand même Wink).

Premièrement, il vous faut rajouter une référence à UIAutomationClient:

automation2

Ensuite, il faut savoir que tout les éléments de l'interface utilisateur sont en fait des AutomationElement. Ces éléments sont contenus dans une structure (en arbre) qui a comme "élément racine" (AutomationElement.RootElement) le bureau Windows. Ainsi, pour avoir accès à un élément d'une application particulière, vous pouvez:

  • parcourir récursivement l'ensemble des AutomationElement qui sont affichés à l'écran, puis une fois que vous avez trouvé celui qui correspond à l'application "hôte", vous parcourez l'ensemble des AutomationElement de cette application jusqu'à arriver à l'élement que vous voulez
  • ou bien, vous pouvez récupérer le handle du processus de l'application hôte puis à partir de là, utiliser ce handle pour récupérer l'AutomationElement correspondant à l'application hôte. Une fois que cela sera fait, il ne vous restera plus qu'a parcourir l'ensemble des AutomationElement de cette application jusqu'à arriver à l'élement que vous voulez

Pour que cela soit plus clair, voici un petit exemple:

// On démarre le processus

Process p = Process.Start("notepad");

 

Thread.Sleep(2000);

 

if (p.MainWindowHandle != IntPtr.Zero)

{

      // On récupère l'AutomationElement depuis le handle du processus

      AutomationElement notepadApplication = AutomationElement.FromHandle(p.MainWindowHandle);

}

Notez qu'ici, je lance un processus Win32 (notepad) mais que cela fonctionnerait également avec une application WPF. Pour les plus curieux, la pause de 2 secondes (Sleep) est nécessaire afin de s'assurer que le processus est bien complètement lancé avant de passer à la suite.

Toujours dans le cadre de notre script d'automatisation d'UI, voyons comment nous allons pouvoir déplacer et redimensionner la fenêtre de notre processus (notepad).

Pour cela, nous allons utiliser des Patterns. Il en existe un certain nombre (18 pour être exact: DockPattern, GridPattern, ScrollPattern, InvokePattern, etc....) mais sachez que chacun d'entre eux représente en fait ce que les élements de votre interface utilisateur peuvent faire. Par exemple, vous allez utiliser un "InvokePattern" pour les contrôles qui peuvent-être invoqués (boutons) ou le "TextPattern" pour les contrôles d'édition (textboxes), etc...

Pour ce qui concerne le déplacement et le redimensionnement, nous allons utiliser un "TransformPattern" (les habitués de WPF ne seront pas surpris):

// On vérifie que l'on peut appliquer un TransformPattern sur cet élément

TransformPattern tranform = notepadApplication.GetCurrentPattern(TransformPattern.Pattern) as TransformPattern;

 

if (tranform != null)

{

    // Si c'est OK, on redimensionne et on déplace.

    tranform.Resize(this.Width, this.Height);

    tranform.Move(this.Left + this.Width + 25, this.Top);

}

Comme vous pouvez le constater, le code est plutôt simple et parle de lui-même: on commence par vérifier que le pattern "Transform" est bien disponible pour l'AutomationElement sur lequel on travaille puis on applique le redimensionnement et le déplacement.

Notre application (Notepad) étant maitenant lancée, voyons comment nous allons pouvoir simuler un clic sur le bouton "Fichier" (File):

 // On cherche à localiser l'élément de l'interface qui porte le nom "File" et qui est de type MenuItem: on pose les conditions de la recherche

PropertyCondition fileMenuCondition = new PropertyCondition(AutomationElement.NameProperty, "File");

PropertyCondition fileMenuItemCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.MenuItem);

 

AndCondition andConditions = new AndCondition(fileMenuCondition, fileMenuItemCondition);

 

// On lance la recherche de l'élément dans l'interface graphique

AutomationElement fileElementMenu = notepadApplication.FindFirst(TreeScope.Descendants, andConditions);

 

if (fileElementMenu != null)

{

     object patternObject;

 

     // On voit si l'élément peut-être plier/déplier

     bool result = fileElementMenu.TryGetCurrentPattern(ExpandCollapsePattern.Pattern, out patternObject);

 

     ExpandCollapsePattern pattern = patternObject as ExpandCollapsePattern;

 

     // Et on le déplie

     if (pattern != null)

     {

        pattern.Expand();

     }

}

 Ici, on commence par poser 2 conditions: la première, c'est que l'AutomationElement que l'on recherche doit s'appeller "File". La seconde, c'est qu'il doit-être de type MenuItem. Une fois les conditions posées, on effectue une recherche sur l'AutomationElement parent (autrement dit l'AutomationElement représentant l'application Notepad) au moyen de la méthode FindFirst.

Si l'on trouve bien l'élément correspondant à nos critères de recherche, alors on vérifie si on peut lui appliquer le pattern ExpandCollapsePattern et si oui, on appelle la méthode Expand !

Rien que pour vos yeux, voici le code permettant de simuler un clic sur le bouton "Fermer" (Close):

 // On cherche à localiser l'élément de l'interface qui porte le nom "Close"

PropertyCondition closeMenuCondition = new PropertyCondition(AutomationElement.NameProperty, "Close");

 

// On lance la recherche de l'élément dans l'interface graphique

AutomationElement closeElementMenu = notepadApplication.FindFirst(TreeScope.Descendants, closeMenuCondition);

 

if (closeElementMenu != null)

{

     object patternObject;

 

     // On voit si l'élément peut-être cliquer

     bool result = closeElementMenu.TryGetCurrentPattern(InvokePattern.Pattern, out patternObject);

 

     InvokePattern pattern = patternObject as InvokePattern;

 

     // Et on le clique => fermeture de l'application

     if (pattern != null)

     {

          pattern.Invoke();

     }

}

Comme vous pouvez le voir, utiliser plusieurs conditions de recherche n'est pas toujours nécessaire (mais cela m'aura permis de vous montrer comment le faire Wink)

Comme vous pouvez le constatez, cela n'a rien de bien compliqué et permet même de faire des choses assez intéressantes !

 

Un petit coup de pouce:

Si vous avez bien suivi cet article, vous avez du vous rendre compte que pour le clic sur l'élément "Fichier" du menu, j'ai utilisé un ExpandCollapsePattern et non pas un InvokePattern, comme je l'ai fait pour le bouton "Fermer". 

Vous pourriez (et vous devriez-même) vous demander comment j'ai fait pour savoir quel pattern utiliser. La réponse est simple: UISpy.

UISpy est une application, disponible dans le SDK de Windows, permettant au développeurs et aux testeurs de voir et d'intéragir avec les éléments de l'interface utilisateur d'une application.

Très pratique, cette application vous permet de voir toutes les propriétés des éléments d'une UI:

  • Nom
  • Type de contrôle (textboxe, MenuItem, etc....)
  • Patterns

automation3[1]

Si vous devez faire de l'UI Automation, croyez-moi: cet outil vous sera très précieux !

 

Conclusions:

Pour conclure, je ne saurais que trop vous conseillez de bien penser à prendre en compte ce problème d'accessibilité: comme vous avez pû le voir, avec WPF, il s'agit de quelque chose de très simple à mettre en place. Et n'oubliez jamais que, souvent, vous n'êtes pas les seuls à utiliser les applications que vous développez Wink

Et pour finir sur un esprit plus fun, dîtes-vous bien que c'est le genre de technologie assez sympa qui, mine de rien, peut vous simplifier la vie de temps en temps (Qui a envie d'une application qui télécommande les applications s'exécutant sur un PC ? Big Smile)

J'espère que cet article vous aura plû et/ou vous aidera !

 

Liens:

Voici quelques liens qui vous aideront, si vous désirez en savoir plus:

 

A+

 

 

del.icio.us Tags:

Technorati Tags:
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Posted: mercredi 25 juillet 2007 10:39 par Thomas LEBRUN
Classé sous : , ,

Commentaires

pc152 a dit :

Bonjour Thomas

Très bon article. merci

.net que du bon ;)

# juillet 25, 2007 10:55

brunews a dit :

Salut Thomas,

désolé mais je ne résiste pas au clic "Fermer" de notepad en 1 ligne:

SendMessage(hnotepad, WM_CLOSE, 0, 0);

Allez, je sors.

# juillet 25, 2007 23:03

loicbar a dit :

Moi qui travaille dans l'accessibilité en ce moment... Cela est fort utile!

Thomas, est tu inscris dans un réseau comme Viadeo ou autre? J'aimerai rentrer en contact avec toi.

# juillet 26, 2007 18:06

Thomas LEBRUN a dit :

@Loïc: Content que cela te soit utile.

Pour répondre à ta question: non, je ne suis pas sur les réseaux type Viadeo :)

# juillet 26, 2007 19:02
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Retrouvez-moi aux Microsoft experiences18 ! par Blog de Jérémy Jeanson le 11-06-2018, 22:25

- Office 365: Script PowerShell pour extraire les Teams associés à un utilisateur spécifié par Blog Technique de Romelard Fabrice le 11-06-2018, 13:37

- SharePoint: Extraire les pages publiées dans un site de publishing en CSV par Blog Technique de Romelard Fabrice le 11-06-2018, 11:04

- Office 365: Comment créer un jeu de Pages Modernes dans un Modern Site SharePoint Online en utilisant PowerShell depuis un fichier CSV par Blog Technique de Romelard Fabrice le 10-17-2018, 12:50

- Office 365: Comment Utiliser les Modern Pages dans un Site Intranet SharePoint basé sur le Publishing site par Blog Technique de Romelard Fabrice le 10-16-2018, 15:34

- Office 365: Comment changer le nom “Auteur” dans les pages modernes d'un Modern Site SharePoint Online par Blog Technique de Romelard Fabrice le 10-16-2018, 15:07

- Reprise des articles Codes-Sources de 2011 à 2013 par Blog de Jérémy Jeanson le 08-21-2018, 16:08

- Office 365: Modifier les jeux de couleur dans les Thèmes des pages classiques de SharePoint Online par Blog Technique de Romelard Fabrice le 08-08-2018, 17:27

- Office 365: Modifier les jeux de couleur dans les Thèmes des pages modernes de SharePoint Online par Blog Technique de Romelard Fabrice le 07-04-2018, 13:26

- Office 365: Script PowerShell pour fixer le Quota Warning de toutes les collections d’un tenant par Blog Technique de Romelard Fabrice le 07-03-2018, 14:16