This blog post will describe how to make a simple WPF custom control property accessible for Ranorex.

Make WPF custom controls accessible
Make WPF custom controls accessible

Microsoft UI Automation is the way to make your WPF application accessible for assistive technology products and automated testing tools.

In this sample application we will just add a simple property to a button.
To examine the information, we have to create a so called Automation Peer Class in the project.

Each UI control has to have an Automation Peer Class, and out of these classes a tree of such elements is created.
This tree of peer automation objects parallels the tree of user interface elements to UI Automation.
UI Automation elements are pieces of user interface that are visible to UI Automation clients.
Such as, application windows, panes, buttons, tooltips, list boxes and list items.

These UI Automation elements are exposed to clients as an UI Automation tree.
The tree is created by navigating from one element to another.
Navigation through the peer tree is enabled by calling the object’s GetChildren and GetParent methods.
The navigation among WPF elements within a control is supported by the peer’s implementation of the GetChildrenCore method.
This method is used to build up the tree of automation peers.

So the first step is to create such an Automation Peer Class, which in our case derives from the “ButtonAutomationPeer” class.
The naming convention of such classes is to start with the control class name and end with “AutomationPeer”.
So the correspondent Automation Peer Class of our CustomButton class is “CustomButtonAutomationPeer”.
If you have a custom control, which derives from Control, the custom peer class has to derive from FrameworkElementAutomationPeer.

public class CustomButtonAutomationPeer : ButtonAutomationPeer

The next step is to overwrite the “OnCreateAutomationPeer” method in the class of the custom button.
This method returns an instance of the “CustomButtonAutomationPeer” class.
Such Peer classes hold information about the control’s characteristics, features and client application.

protected override AutomationPeer OnCreateAutomationPeer()
{
  return new CustomButtonAutomationPeer(this);
}

As next step the GetPattern method of the AutomationPeer class has to be overwritten.
Because we just overwrite one of the core methods to publish our new property, there is no need to implement one of the Pattern Interfaces.
If you have to create such a Pattern you also have to return an instance of the class, which implements the appropriate Provider.
Please mention that Ranorex does not support all of the Providers.
Ranorex supports the “IInvokeProvider”, the “IRangeValueProvider”, the “IToggleProvider” and the IValueProvider.
For this sample we could also implement the IValueProvider to populate the value of the specific property, but overwriting one Core method is easier.

public override object GetPattern(PatternInterface patternInterface)
{
  return base.GetPattern(patternInterface);
}

As the Automation code also gets the information of the different controls via public methods of the peer class, it is required to overwrite methods which end with “Core”, but only those which differ from the base automation peer class.

The implementation of “GetAutomationControlTypeCore” describes the control by returning a ControlType value.
In this case we choose Button, as our control is still a Button.
You can of course choose another type or ControlType.Custom, but this would require extra work and it is harder for client products to anticipate the control structure, keyboard interaction, and possible control patterns.

protected override AutomationControlType GetAutomationControlTypeCore()
{
  return AutomationControlType.Button;
}

Let’s choose GetItemStatusCore to populate the specific property of our custom control, because this “ItemStatusCore” is not very relevant for testing purposes.
But of course you can also choose one of the other methods and overwrite them.

protected override string GetItemStatusCore()
{
  return owner.testProp1;
}

You can also overwrite the peer implementation of the core methods by including AutomationProperties attributes as you can see in the XAML file.
There we overwrite the GetItemTypeCore method via AutomationProperties.ItemType=”{BindingPath=testProp}”.


    
        CustomButton
    

protected override string GetItemTypeCore()
{
  return base.GetItemTypeCore();
}

Now we are able to execute our small sample program and we will see that after clicking the button, the values of the overwritten properties are going to change.

Download this sample solution.

There are also many other samples for more complex controls in the Internet, but in this case we just want to give a brief overview of how to make custom properties accessible for Ranorex.

You might also like these articles