Server-Side UI Automation Provider Implementation

This section describes how to implement a server-side UI Automation provider for a custom control.

The implementation for Windows Presentation Foundation (WPF) elements and non-WPF elements (such as those designed for Windows Forms) is fundamentally different. WPF elements provide support for UI Automation through a class derived from AutomationPeer. Non-WPF elements provide support through implementations of provider interfaces.

This topic contains the following sections.

  • Security Considerations
  • Provider Implementation by Windows Presentation Foundation Elements
  • Provider Implementation by non-WPF Elements
  • Related Topics

Security Considerations

Providers should be written so that they can work in a partial-trust environment. Because UIAutomationClient.dll is not configured to run under partial trust, your provider code should not reference that assembly. If it does so, the code may run in a full-trust environment but then fail in a partial-trust environment.

In particular, do not use fields from classes in UIAutomationClient.dll such as those in AutomationElement. Instead, use the equivalent fields from classes in UIAutomationTypes.dll, such as AutomationElementIdentifiers.

Provider Implementation by Windows Presentation Foundation Elements

Custom elements in the WPF framework provide support for UI Automation through classes derived from AutomationPeer or one of its derived classes such as ButtonAutomationPeer. To use these classes, your project must reference PresentationCore.dll.

The peer classes are roughly equivalent to UI Automation control types, but are specific to WPF elements. Specialized peers derive from more general peers. For example, CheckBoxAutomationPeer derives from ButtonBaseAutomationPeer, which in turn derives from FrameworkElementAutomationPeer.

Like non-WPF providers, peers support control patterns by providing implementations of interfaces in the System.Windows.Automation.Provider namespace, such as IInvokeProvider. The control pattern interfaces can be implemented by the peer itself, or by another object. The peer's implementation of GetPattern returns the object that supports the specified pattern.

The interfaces implemented by a custom provider are explicitly declared if the owning element derives directly from Control. For example, the following code declares a peer for a Control that implements a range value.

public class RangePeer1 : FrameworkElementAutomationPeer, IRangeValueProvider { }

If the owning control derives from a specific type of control such as RangeBase, the peer can be derived from an equivalent derived peer class. In this case, the peer would derive from RangeBaseAutomationPeer, which supplies a base implementation of IRangeValueProvider. The following code shows the declaration of such a peer.

public class RangePeer2 : RangeBaseAutomationPeer { }

For an example implementation, see NumericUpDown Custom Control with Theme and UI Automation Support Sample.

Requirements for Windows Presentation Foundation Peers

In order to communicate with UI Automation, your control must implement the following main areas of functionality:

Functionality Implementation

Expose the control to UI Automation

Override OnCreateAutomationPeer for your custom control so that it returns your provider object, which is derived directly or indirectly from AutomationPeer.

Provide property values

Override property-get methods of the base peer class (for example, System.Windows.Automation.Peers.AutomationPeer.GetAcceleratorKey) and of any additional control pattern interfaces implemented by your custom peer (for example, System.Windows.Automation.Provider.IToggleProvider.ToggleState).

Enable the client to interact with the control

Override methods of the base peer class (for example, System.Windows.Automation.Peers.ToggleButtonAutomationPeer.System.Windows.Automation.Provider.IToggleProvider.Toggle and of any additional control pattern interfaces implemented by your custom peer. In your provider's implementation of GetPattern, return the object that supports the specified control pattern. Note that if your control doesn't have a custom implementation of a pattern, you can call the base type's implementation of GetPattern to retrieve either its implementation, or a null reference if the pattern is not supported for this control type.

Raise events

Override RaiseAutomationEvent and RaisePropertyChangedEvent.

Peer Properties

Applications can override the default properties of UI Automation peers by using AutomationProperties. For example, the following XML code creates a button that has two customized UI Automation properties.

<Button AutomationProperties.Name="Special" AutomationProperties.HelpText="This is a special button."/>

Peer Navigation

Navigation among WPF elements within a user interface is supported by the peer's implementation of GetChildren method. The UI Automation system calls this method to build up a tree of subelements contained within a control; for example, list items in a list box.

Provider Implementation by non-WPF Elements

Custom controls that are not part of the WPF framework, but that are written in managed code (most often these are Windows Forms controls), provide support for UI Automation by implementing interfaces. Every element must implement at least one of the interfaces listed in the first table in the next section. In addition, if the element supports one or more control patterns, it must implement the appropriate interface for each control pattern.

Your UI Automation provider project must reference the following assemblies:

  • UIAutomationProviders.dll

  • UIAutomationTypes.dll

  • WindowsBase.dll

This section contains the following subsections.

  • Provider Interfaces
  • Requirements for Non-WPF Providers
  • Property Values in Non-WPF Providers
  • Events in Non-WPF Providers
  • Non-WPF Provider Navigation
  • Non-WPF Provider Reparenting
  • Non-WPF Provider Repositioning

Provider Interfaces

Every UI Automation provider must implement one of the following interfaces.

Interface Description

IRawElementProviderSimple

Provides functionality for a simple control hosted in a window, including support for control patterns and properties.

IRawElementProviderFragment

Inherits from IRawElementProviderSimple. Adds functionality for an element in a complex control, including navigation within the fragment, setting focus, and returning the bounding rectangle of the element.

IRawElementProviderFragmentRoot

Inherits from IRawElementProviderFragment. Adds functionality for the root element in a complex control, including locating a child element at specified coordinates and setting the focus state for the entire control.

The following interfaces provide added functionality but are not required to be implemented.

Interface Description

IRawElementProviderAdviseEvents

Enables the provider to track requests for events.

IRawElementProviderHwndOverride

Enables repositioning of window-based elements within the UI Automation tree of a fragment.

All other interfaces in the System.Windows.Automation.Provider namespace are for control pattern support.

Requirements for Non-WPF Providers

In order to communicate with UI Automation, your control must implement the following main areas of functionality:

Functionality Implementation

Expose the provider to UI Automation

In response to a WM_GETOBJECT message sent to the control window, return the object that implements IRawElementProviderSimple (or a derived interface). For fragments, this must be the provider for the fragment root.

Provide property values

Implement GetPropertyValue to provide or override values.

Enable the client to interact with the control

Implement interfaces that support control patterns, such as IInvokeProvider. Return these pattern providers in your implementation of GetPatternProvider.

Raise events

Call one of the static methods of AutomationInteropProvider to raise an event that a client can listen for.

Enable navigation and focusing within a fragment

Implement IRawElementProviderFragment for each element within the fragment. (Not necessary for elements that are not part of a fragment.)

Enable focusing and location of child element in a fragment

Implement IRawElementProviderFragmentRoot. (Not necessary for elements that are not fragment roots.)

Property Values in Non-WPF Providers

UI Automation providers for custom controls must support certain properties that can be used by the automation system as well as by client applications. For elements that are hosted in windows (HWNDs), UI Automation can retrieve some properties from the default window provider, but must obtain others from the custom provider.

Providers for HWND based controls do not usually need to provide the following properties (identified by field values):

NoteNote:

The RuntimeIdProperty of a simple element or fragment root hosted in a window is obtained from the window; however, fragment elements below the root (such as list items in a list box) must provide their own identifiers. For more information, see GetRuntimeId.

The IsKeyboardFocusableProperty should be returned for providers hosted in a Windows Forms control. In this case, the default window provider may be unable to retrieve the correct value.

The NameProperty is usually supplied by the host provider. For example, if a custom control is derived from Control, the name is derived from the Text property of the control.

For example code, see Return Properties from a UI Automation Provider.

Events in Non-WPF Providers

UI Automation providers should raise events to notify client applications of changes in the state of the UI. The following methods are used to raise events.

Method Description

RaiseAutomationEvent

Raises various events, including events triggered by control patterns.

RaiseAutomationPropertyChangedEvent

Raises an event when a UI Automation property has changed.

RaiseStructureChangedEvent

Raises an event when the structure of the UI Automation tree has changed; for example, by the removal or addition of an element.

The purpose of an event is to notify the client of something taking place in the user interface (UI), whether or not the activity is triggered by the UI Automation system itself. For example, the event identified by InvokedEvent should be raised whenever the control is invoked, either through direct user input or by the client application calling Invoke.

To optimize performance, a provider can selectively raise events, or raise no events at all if no client application is registered to receive them. The following methods are used for optimization.


Method Description

ClientsAreListening

This static property specifies whether any client applications have subscribed to UI Automation events.

IRawElementProviderAdviseEvents

The provider's implementation of this interface on a fragment root enables it to be advised when clients register and unregister event handlers for events on the fragment.

Non-WPF Provider Navigation

Providers for simple controls such as a custom button hosted in a window (HWND) do not need to support navigation within the UI Automation tree. Navigation to and from the element is handled by the default provider for the host window, which is specified in the implementation of HostRawElementProvider. When you implement a provider for a complex custom control, however, you must support navigation between the root node of the fragment and its descendants, and between sibling nodes.

NoteNote:

Elements of a fragment other than the root must return a null reference from HostRawElementProvider, because they are not directly hosted in a window, and no default provider can support navigation to and from them.

The structure of the fragment is determined by your implementation of Navigate. For each possible direction from each fragment, this method returns the provider object for the element in that direction. If there is no element in that direction, the method returns a null reference.

The fragment root supports navigation only to child elements. For example, a list box returns the first item in the list when the direction is FirstChild, and the last item when the direction is LastChild. The fragment root does not support navigation to a parent or siblings; this is handled by the host window provider.

Elements of a fragment that are not the root must support navigation to the parent, and to any siblings and children they have.

Non-WPF Provider Reparenting

Pop-up windows are actually top-level windows, and so by default appear in the UI Automation tree as children of the desktop. In many cases, however, pop-up windows are logically children of some other control. For example, the drop-down list of a combo box is logically a child of the combo box. Similarly, a menu pop-up window is logically a child of the menu. UI Automation provides support to reparent pop-up windows so that they appear to be children of the associated control.

To reparent a pop-up window:

  1. Create a provider for the pop-up window. This requires that the class of the pop-up window is known in advance.

  2. Implement all properties and patterns as usual for that pop-up, as though it were a control in its own right.

  3. Implement the HostRawElementProvider property so that it returns the value obtained from HostProviderFromHandle, where the parameter is the window handle of the pop-up window.

  4. Implement Navigate for the pop-up window and its parent so that navigation is handled properly from the logical parent to the logical children, and between sibling children.

When UI Automation encounters the pop-up window, it recognizes that navigation is being overridden from the default, and skips over the pop-up window when it is encountered as a child of the desktop. Instead, the node will only be reachable through the fragment.

Reparenting is not suitable for cases where a control can host a window of any class. For example, a rebar can host any type of HWND in its bands. To handle these cases, UI Automation supports an alternative form of HWND relocation, as described in the next section.

Non-WPF Provider Repositioning

UI Automation fragments may contain two or more elements that are each contained in a window (HWND). Because each HWND has its own default provider that considers the HWND to be a child of a containing HWND, the UI Automation tree will, by default, show the HWNDs in the fragment as children of the parent window. In most cases this is desirable behavior, but sometimes it can lead to confusion because it does not match the logical structure of the UI.

A good example of this is a rebar control. A rebar contains bands, each of which can in turn contain an HWND-based control such as a toolbar, an edit box, or a combo box. The default window provider for the rebar HWND sees the band control HWNDs as children, and the rebar provider sees the bands as children. Because the HWND provider and the rebar provider are working in tandem and combining their children, both the bands and the HWND-based controls appear as children of the rebar. Logically, however, only the bands should appear as children of the rebar, and each band provider should be coupled with the default HWND provider for the control it contains.

To accomplish this, the fragment root provider for the rebar exposes a set of children representing the bands. Each band has a single provider that may expose properties and patterns. In its implementation of HostRawElementProvider, the band provider returns the default window provider for the control HWND, which it obtains by calling HostProviderFromHandle, passing in the control's window handle. Finally, the fragment root provider for the rebar implements the IRawElementProviderHwndOverride interface, and in its implementation of GetOverrideProviderForHwnd it returns the appropriate band provider for the control contained in the specified HWND.

See Also

Tasks

Expose a Server-side UI Automation Provider
Return Properties from a UI Automation Provider
Raise Events from a UI Automation Provider
Enable Navigation in a UI Automation Fragment Provider
Support Control Patterns in a UI Automation Provider

Concepts

UI Automation Providers Overview

Other Resources

Simple Provider Sample
Fragment Provider Sample