Med UI automation APIerne kan du få fat i og interagere med UI Elementer på desktoppen og i andre programmer. UI Elementet (kontrollen) skal understøtte UI Automation, hvilket langt de fleste gør. UI automatisering har, som jeg ser der, to overordnede anvendelser, Accessibility og UI Interoperability.

Et lille eksempel kunne være at jeg gerne lære mine børn matematik, velvidende at de sikkert får lyst til mere, så jeg vil ikke selv lave en calculator, men bare genbruge den Calculator (calc.exe) der kommer med Windows. Tænk selv et sjovere UI ind med æbler, bananer og pærer ;-).

Anyways, jeg skal have fat i Calculator programmet, samt fat i de knapper jeg vil bruge og resultatfeltet (UI Elementer). Det gør jeg nedenfor:

Process calcInstance = Process.Start("calc.exe");


//Window handle is initialized asynchronously, so let wait until we have a handle
while (calcInstance.MainWindowHandle == IntPtr.Zero) { System.Threading.Thread.SpinWait(1000000); } AutomationElement calculator = AutomationElement.FromHandle(calcInstance.MainWindowHandle); // Get all buttons AutomationElementCollection buttons = calculator.FindAll(TreeScope.Descendants, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button)); AutomationElement btnOne = null; AutomationElement btnPlus = null; AutomationElement btnEquals = null; AutomationElement btnClear = null; AutomationElement btnFour = null; AutomationElement btnMaximize = null; AutomationElement resultPane = null; //get reference to buttons – Use “UI Spy” to get names and Automation IDs from applications foreach (AutomationElement button in buttons) { switch (button.Current.Name) { case "1": btnOne = button; break; case "Maximize": btnMaximize = button; break; case "4": btnFour = button; break; case "Add": btnPlus = button; break; case "Clear": btnClear = button; break; case "Equals": btnEquals = button; break; default: break; } } try { //invoke buttons InvokeControl(btnClear); InvokeControl(btnOne); InvokeControl(btnOne); InvokeControl(btnOne); InvokeControl(btnPlus); InvokeControl(btnFour); InvokeControl(btnEquals); } catch (Exception ex) { Console.WriteLine("E: " + ex.Message); }

//find all text controls
AutomationElementCollection txt= calculator.FindAll(TreeScope.Descendants, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Text)); foreach (AutomationElement t in txt) { //the automation id of the result pane is 150 if (t.Current.AutomationId.Equals("150")) resultPane = t; } Console.WriteLine("=" + resultPane.Current.Name); Console.ReadKey(); }

På MSDN fandt jeg lidt kode, til at få eksekveret kommandoen der ligger bag mit AutomationElement. Det interessante i nedenstående er at der bruges invokepattern. Der findes en række forskellige patterns man kan bruge, alt afhængig af hvad du ønsker at gøre med AutomationElementet.

static void InvokeControl(AutomationElement targetControl)
{
    InvokePattern invokePattern = null;
    try
    {
        invokePattern =
            targetControl.GetCurrentPattern(
            InvokePattern.Pattern) as InvokePattern;
    }
    catch (ElementNotEnabledException)
    {
        return;
    }
    catch (InvalidOperationException)
    { return; }
    invokePattern.Invoke();
}

For at identificere de enkelte UI elementer, kan man bruge “UI Spy”, som kommer sammen med Visual Studio. Nedenfor har jeg startet UI Spy og en Calculator. Ved at holde ctrl nede, så fokuserer UI Spy på det UI element der er under musens cursor. Når der er fokuseret, så kan jeg se properties på UI elementet.

clip_image001