Click here to Skip to main content
Click here to Skip to main content

UI Automation Framework using WPF

, 11 Mar 2009
Rate this:
Please Sign up or sign in to vote.
This article shows how to make use of UI Automation Framework with WPF

Introduction

This article shows how to make use of UI Automation Framework using WPF to develop an UI Automated application. The UI Automation Library is included in the .NET Framework 3.0/3.5. The concept seems to be straightforward. Every UI control is an "AutomationElement" which can be found through searching from the Parent "AutomationElement". The top AutomationElement is defined as the "RootElement", which is the desktop.

Another way to get the AutomationElement Object to a given Window is by starting a "Process", and then using the Process MainWindowHandle to get the AutomationElement object.

Background

I am sharing information on this framework because I found it very interesting and had a very hard time developing a full featured application. On the internet, I found a very small amount or I must say not adequate amount of material. So I thought of writing some code-sample to help others and may find useful. Here, I am not going to explain what is UI Automation Framework and its details. You can find a theoretical article on internet/MSDN. Here I will provide how to make use of the UI Automation libraries, and how to play with this framework using WinForm controls.

I was given the scenario, where there is already an application developed in WinForms using .NET Framework 2.0. And UI Automation application is developed in WPF using .NET Framework 3.5. The sample application gives you an idea of how to write UI Automation application using UI Automation Framework, i.e., how to use UI Automation Class Libraries, how to find controls and write automated test cases.

The solution contains 2 projects, one project is WinForms application targeting .NET Framework 2.0 and the second project is WPF application targeting .NET Framework 3.5. The WPF application is basically a test that invokes WinForms application, which has some controls like Textbox, dropdown, checkbox, grid, etc. I showed single TestCase execution on a single button click, but once you get the idea, you can play with it and write a series of test cases that can be executed in a single action.

Note: When you compile this solution, I set output path for WinForm application to bin folder of WPF application just to make it easier to understand and load the application.

Using the Code

How to Load Application and find Root Instance of target application

Automation.RootElement: It represents the desktop, and all other applications on desktop appear as child windows of this RootElement. The below code shows how to find the target instance of the application from the desktop.

private void LoadApplication_Click(object sender, RoutedEventArgs e)
{
  //Start the client application
  this._clientProcess = Process.Start
	(this._targetApplicationPath + @"\" + this._targetApplicationName);

  Thread.Sleep(100);

  int count = 0;

  do
  {
    ++count;
    //Get the Root Element of client application from the Desktop tree
    this._clientAppRootInstance = 
	AutomationElement.RootElement.FindFirst(TreeScope.Children,
        	new PropertyCondition(AutomationElement.NameProperty, "SampleForm"));

    Thread.Sleep(100);
  }
  while (this._clientAppRootInstance == null && count < 10);

  if (this._clientAppRootInstance == null)
  {
     MessageBox.Show("SampleForm application instance not found. 
			Close application and try again!!!");
     return;
  }
}
How to find Textbox and use of TextPattern
  • AutomationElement: This object exposes common properties of the UI elements they represent. One of these properties is the control type, which defines its basic appearance and functionality as a single recognizable entity (e.g., a button or check box). In addition, elements expose control patterns that provide properties specific to their control types. Control patterns also expose methods that enable clients to get further information about the element and to provide input.
  • TreeScope: It represents enumeration which has values to specify the scope of element within the UI Automation tree or in Root element.
  • PropertyCondition: It represents the condition that tests whether property has a specified value.
  • AndCondition: It represents the combination of 2 or more conditions that must all be true for a particular match.
private void TextBoxTest_Click(object sender, RoutedEventArgs e)
{
   if (this._clientAppRootInstance != null)
   {
     //Get the textbox (appears as Document Control Type) instance from 
     //application root instance as it will child
     //and add the AndCondition so minimize the search time in tree
     textBoxInstance = this._clientAppRootInstance.FindFirst(TreeScope.Children,
                           new AndCondition(
                           new PropertyCondition
			(AutomationElement.AutomationIdProperty, "txtDocument"),
                           new PropertyCondition
			(AutomationElement.ControlTypeProperty, ControlType.Document)
                            ));
     if (textBoxInstance == null)
     {
       MessageBox.Show("Textbox instance not found");
     }
     else
     {
       //Set focus to textbox
       textBoxInstance.SetFocus();
       //Use SendKeys to send text
       System.Windows.Forms.SendKeys.SendWait(_tempText);
     }
   }
} 

UI Automation supports different types of patterns depending upon the controls. Below is the code sample of TextPattern.

private void CompareText_Click(object sender, RoutedEventArgs e)
{
  //Control that accept the values as represented as TextPattern
  TextPattern textboxPattern = 
	(TextPattern)textBoxInstance.GetCurrentPattern(TextPattern.Pattern);
  if (textboxPattern == null)
  {
    MessageBox.Show("Textbox instance not found.");
  }
  else
  {
    string enteredText = textboxPattern.DocumentRange.GetText(-1).Trim();
    if (string.Equals(enteredText, _tempText, 
	StringComparison.InvariantCultureIgnoreCase))
    {
      MessageBox.Show("Compare test passed");
    }
    else
    {
      MessageBox.Show("Compare test failed.");
    }
   }
}
How to select value from dropdown and use of ExpandCollapsePattern and SelectionItemPattern

Below is the code sample that shows how to select value from combobox. Combobox supports ExpandCollapsePattern and SelectionItemPattern. Combobox contains List as children and List contains the collection of ListItems in combobox.

private void ComboBoxTest_Click(object sender, RoutedEventArgs e)
{
   if (this._clientAppRootInstance != null)
   {
     //Get the combo box instance from application root instance as its 
     //child instance and find by its name
     AutomationElement comboboxInstance = 
	this._clientAppRootInstance.FindFirst(TreeScope.Children,
         new PropertyCondition(AutomationElement.AutomationIdProperty, "cmbMonth"));
     if (comboboxInstance == null)
     {
        MessageBox.Show("ComboBox instance not found.");
     }
     else
     {
         //Get the List child control inside the combo box
        AutomationElement comboboxList = comboboxInstance.FindFirst(TreeScope.Children,
              new PropertyCondition
		(AutomationElement.ControlTypeProperty, ControlType.List));

         //Get the all the listitems in List control
         AutomationElementCollection comboboxItem = 
			comboboxList.FindAll(TreeScope.Children,
             new PropertyCondition(AutomationElement.ControlTypeProperty, 
						ControlType.ListItem));

         //Combo Box support 2 patterns, ExpandCollapsePatterna and SelectionItemPattern
         //Expand the combobox
         ExpandCollapsePattern expandPattern = 
		(ExpandCollapsePattern)comboboxInstance.GetCurrentPattern
		(ExpandCollapsePattern.Pattern);

         expandPattern.Expand();

           //Index to set in combo box
           AutomationElement itemToSelect = comboboxItem[comboboxItem.Count - 7];

           //Finding the pattern which need to select
          Object selectPattern = null;
          if (itemToSelect.TryGetCurrentPattern
		(SelectionItemPattern.Pattern, out selectPattern))
          {
             ((SelectionItemPattern)selectPattern).Select();
          }
       }
   }
}
How to find button and use of InvokePattern

Button supports InvokePattern, which represents the control that initiates or performs a single action. Like code executes on button click, it does not maintain the state when activated.

private void AddDataRowTest_Click(object sender, RoutedEventArgs e)
{
   if (this._clientAppRootInstance != null)
   {
      //Get the Add Button instance from root instance, finding it by name 
      //and its child in root instance
      AutomationElement buttonAddInstance = 
	this._clientAppRootInstance.FindFirst(TreeScope.Children,
        	new PropertyCondition(AutomationElement.AutomationIdProperty, "btnAdd"));
      if (buttonAddInstance == null)
      {
         MessageBox.Show("Add button instance not found");
      }
      else
      {
         //Button support Invoke Pattern
         InvokePattern buttonPattern = 
	    (InvokePattern)buttonAddInstance.GetCurrentPattern(InvokePattern.Pattern);
         //Once get the pattern then calling Invoke method on that
         buttonPattern.Invoke();
      }
   }
}
How to attach Event Handler on control in target application

The code sample below shows how to create and attach an event handler on checkbox in the target application:

private void CheckBoxTest_Click(object sender, RoutedEventArgs e)
{
   if (this._clientAppRootInstance != null)
   {
      //Get the checkbox instance from root application instance and 
      //it appears as child in the tree and finding by its name
      AutomationElement checkBoxInstance = 
	this._clientAppRootInstance.FindFirst(TreeScope.Children,
         new PropertyCondition(AutomationElement.AutomationIdProperty, "chkCheckBox"));
      
         if (checkBoxInstance == null)
         {
            MessageBox.Show("Checkbox instance not found");
         }
         else
         {
            //Create EventHandler for CheckBox
            AutomationPropertyChangedEventHandler checkBoxEvent = 
	    new AutomationPropertyChangedEventHandler(CheckBoxIsChecked_EventHandler);

            //Attaching the EventHandler
            Automation.AddAutomationPropertyChangedEventHandler(_clientAppRootInstance, 
		TreeScope.Children, checkBoxEvent, AutomationElement.NameProperty);
         }
    }
}

Below is the Event Handler code which executes when user checks the checkbox on target application:

private void CheckBoxIsChecked_EventHandler(object sender, AutomationEventArgs e)
{
    //If CheckBox is checked on target application then this get executed
    AutomationElement ar = sender as AutomationElement;

    MessgeBox.Show("Checkbox IsChecked event executed.");
}

I hope this post is useful to others. Please rate this article and provide your valuable feedback.

History

  • 11th March, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Saki Sachin
Software Developer (Senior)
United States United States
Sachin has been developing software professionally for more than five years. Mostly working with .NET Framework 3.5/3.0/2.0/1.x, Windows Communication Foundation (WCF), Windows Presentation Foundation (WPF)\Smart Client, ASP.NET 3.5/2.0/1.x (WebForm), XAML, ASP.NET AJAX 1.0, C# (3.0), LINQ, VB.NET, ADO.NET, WinForm, Web Services, MS Sync Framework, Window Services, UI Automation Framework, SQL Server and good experience in agile/scrum development methodology.

Comments and Discussions

 
GeneralIs there something similar for JAVA UIs Pinmembersuresh_ece13-Jan-11 1:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140718.1 | Last Updated 11 Mar 2009
Article Copyright 2009 by Saki Sachin
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid