à l'aide de C# et UI Automation pour saisir le contenu de l'inconnu de contrôle de type
Dans l'image ci-dessous il y a une région qui a un inconnu (personnalisé) de la classe. Ce n'est pas une Grille ou un Tableau.
J'ai besoin d'être en mesure:
- sélectionner des Lignes dans ce domaine
- pour saisir une Valeur dans chaque cellule
Le problème puisque ce n'est pas un type commun élément - je n'ai aucune idée de comment google ce problème et le résoudre moi-même. Jusqu'à présent, le code est le suivant:
Process[] proc = Process.GetProcessesByName("programname");
AutomationElement window = AutomationElement.FromHandle(proc [0].MainWindowHandle);
PropertyCondition xEllist2 = new PropertyCondition(AutomationElement.ClassNameProperty, "CustomListClass", PropertyConditionFlags.IgnoreCase);
AutomationElement targetElement = window.FindFirst(TreeScope.Children, xEllist2);
J'ai déjà essayé à la menace de cette Zone comme une zone de texte, sous forme d'une grille, comme une zone de liste déroulante, mais rien n'a résolu mon problème jusqu'à présent. Ne quelqu'un a des conseils sur la façon de saisir les données de cette zone et en parcourir les lignes?
EDIT: désolé j'ai fait une fausse hypothèse. En fait, l'en-tête(colonne 1, colonne 2, colonne 3) et la "partie inférieure" de cette région sont de contrôle différents types de!!
Grâce à Wininspector j'ai été en mesure de creuser de plus amples renseignements au sujet de ces types de contrôle:
- L'en-tête contient les propriétés suivantes: HeaderControl 0x056407DC (90441692) de l'Atome: #43288 0xFFFFFFFF (-1)
- et la moitié inférieure a ces: ListControl 0x056408A4 (90441892) de l'Atome: #43288 0x02A6FDA0 (44498336)
Le code que j'ai montré plus tôt - extrait de la "Liste" élément, voici donc la mise à jour:
Process[] proc = Process.GetProcessesByName("programname");
AutomationElement window = AutomationElement.FromHandle(proc [0].MainWindowHandle);
//getting the header
PropertyCondition xEllist3 = new PropertyCondition(AutomationElement.ClassNameProperty, "CustomHeaderClass", PropertyConditionFlags.IgnoreCase);
AutomationElement headerEl = XElAE.FindFirst(TreeScope.Children, xEllist3);
//getting the list
PropertyCondition xEllist2 = new PropertyCondition(AutomationElement.ClassNameProperty, "CustomListClass", PropertyConditionFlags.IgnoreCase);
AutomationElement targetElement = window.FindFirst(TreeScope.Children, xEllist2);
Après lui donnant une autre pensée que j'ai essayé d'obtenir tous les noms de colonne:
AutomationElementCollection headerLines = headerEl.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.HeaderItem));
string headertest = headerLines[0].GetCurrentPropertyValue(AutomationElement.NameProperty) as string;
textBox2.AppendText("Header 1: " + headertest + Environment.NewLine);
Malheureusement en mode debug élément nombre dans "headerLines" est 0 de sorte que le programme génère une erreur.
Edit 2: Merci pour la réponse ci-dessous - j'ai installé non géré UI Automation, qui détient de meilleures possibilités que le défaut de l'UIA. http://uiacomwrapper.codeplex.com/
Comment utilisez-vous l'héritage de modèle à s'emparer des données de l'inconnu de contrôle de type?
if((bool)datagrid.GetCurrentPropertyValue(AutomationElementIdentifiers.IsLegacyIAccessiblePatternAvailableProperty))
{
var pattern = ((LegacyIAccessiblePattern)datagrid.GetCurrentPattern(LegacyIAccessiblePattern.Pattern));
var state = pattern.Current.State;
}
Modifier 3. IUIAutoamtion approche (non ouvrables à compter de maintenant)
_automation = new CUIAutomation();
cacheRequest = _automation.CreateCacheRequest();
cacheRequest.AddPattern(UiaConstants.UIA_LegacyIAccessiblePatternId);
cacheRequest.AddProperty(UiaConstants.UIA_LegacyIAccessibleNamePropertyId);
cacheRequest.TreeFilter = _automation.ContentViewCondition;
trueCondition = _automation.CreateTrueCondition();
Process[] ps = Process.GetProcessesByName("program");
IntPtr hwnd = ps[0].MainWindowHandle;
IUIAutomationElement elementMailAppWindow = _automation.ElementFromHandle(hwnd);
List<IntPtr> ls = new List<IntPtr>();
ls = GetChildWindows(hwnd);
foreach (var child in ls)
{
IUIAutomationElement iuiae = _automation.ElementFromHandle(child);
if (iuiae.CurrentClassName == "CustomListClass")
{
var outerArayOfStuff = iuiae.FindAllBuildCache(interop.UIAutomationCore.TreeScope.TreeScope_Children, trueCondition, cacheRequest.Clone());
var outerArayOfStuff2 = iuiae.FindAll(interop.UIAutomationCore.TreeScope.TreeScope_Children, trueCondition);
var countOuter = outerArayOfStuff.Length;
var countOuter2 = outerArayOfStuff2.Length;
var uiAutomationElement = outerArayOfStuff.GetElement(0); //error
var uiAutomationElement2 = outerArayOfStuff2.GetElement(0); //error
//...
//I've erased what's followed next because the code isn't working even now..
}
}
Le code a été mis en œuvre grâce à ce numéro:
Comme le résultat:
- countOuter et countOuter2 longueurs = 0
- impossible de sélectionner des éléments (lignes de la liste)
- impossible d'obtenir une QUELCONQUE valeur
- rien ne fonctionne
1. Pourquoi voudrais-je utiliser UIAutomation sur mon propre application? 2. "l'inconnu (personnalisé) de la classe" est synonyme de "inconnu de contrôle de type". 3. "Ce n'est pas votre code?" - exactement (voir p.1).
OriginalL'auteur Alex | 2012-06-22
Vous devez vous connecter pour publier un commentaire.
Vous pourriez vouloir essayer à l'aide de la base de l'INTERFACE utilisateur de l'automatisation des classes. Il exige que vous importez le fichier dll à utiliser en C#. Ajoutez ceci à votre pré-événement de construction (ou de le faire juste une fois, etc):
Vous pouvez ensuite utiliser la IUIAutomationLegacyIAccessiblePattern.
Obtenir les constantes que vous avez besoin pour les appels à partir de:
C:\Program Files\Microsoft SDKs\Windows\v7.1\Include\UIAutomationClient.h
Je suis capable de lire Infragistics Ultragrids de cette façon.
Si c'est trop douloureux, essayez d'utiliser MSAA. J'ai utilisé ce projet comme un point de départ avec MSAA avant de se convertir à l'ensemble de l'UIA de Base: SASM Exemple de Code
----- Édité à l'6/25/12 ------
Je n'hésiterais pas à dire que de trouver le bon "identificateurs" est la partie la plus douloureuse de l'utilisation de la MS UIAutomation choses. Ce qui m'a aidé beaucoup est de créer un simple formulaire de demande que je peux utiliser comme " l'emplacement de l'enregistreur. Essentiellement, vous avez besoin de deux choses:
un moyen de tenir au point, même lorsque vous êtes hors de votre forme de la fenêtre d' La tenue de l'accent
un appel à ElementFromPoint() en utilisant les coordonnées x,y de la souris. Il y a une mise en œuvre de cette dans le CUIAutomation classe.
- Je utiliser la touche CTRL pour dire à mon application pour saisir les coordonnées de la souris (le Système.De Windows.Les formulaires.Le curseur.Position). Je puis obtenir l'élément à partir du point et de manière récursive obtenir de l'élément parent jusqu'à ce que j'arrive sur le bureau.
----- edit sur 6/26/12 -----
Une fois que vous pouvez récursive trouver l'automatisation des identifiants et/ou de noms, vous pouvez facilement modifier le code ici: http://blog.functionalfun.net/2009/06/introduction-to-ui-automation-with.html pour être utilisé avec la Base d'UI Automation classes. Cela vous permettra de construire une chaîne de caractères comme vous le répète, qui peut être utilisé pour identifier un contrôle imbriquée dans une application avec un XPath la syntaxe de style.
J'ai utilisé votre IUIAutomation approche et a réussi à obtenir l'héritage de modèle pour cette "liste". Que dois-je faire ensuite? Comment sélectionner une ligne et saisir des données à partir d'elle? var legacyPattern = dataF.GetCurrentPattern(UiaConstants.UIA_LegacyIAccessiblePatternId) IUIAutomationLegacyIAccessiblePattern;
la longueur de la "var outerArayOfStuff = datagrid.FindAllBuildCache(interop.UIAutomationCore.TreeScope.TreeScope_Children, trueCondition, cacheRequest.Clone());" est 0, les valeurs, les noms(mise en cache, en cours) sont "".. je ne peux même pas sélectionner une seule ligne. ;(
Vous pourriez post comment vous avez construit votre cache de requête. Aussi, essayez d'utiliser FindAll (je pense que c'est ce qu'il est appelé) au lieu de FindAllBuildCache pour commencer. J'ai eu des problèmes de performances à travers le travail, sinon je n'aurais pas utilisé le cache. Je n'ai pas de code en face de moi en ce moment. Je peux ajouter plus si vous en avez besoin.
Pour vous dire la vérité - j'ai utilisé presque tous les moyens de la méthode y est.. (FindAll, FindFirst, FindAllBuildCache). J'ai aussi utilisé trois approches différentes (Gestion de l'UIA, non managé de l'UIA, IUIA). Malheureusement, rien ne semble fonctionner jusqu'à présent. De toute façon, j'ai mis à jour mon post avec la dernière version du code (voir Edit 3). Merci pour les réponses!
OriginalL'auteur chrismead