Caching in UI Automation Clients
This topic introduces caching of UI Automation properties and control patterns.
In UI Automation, caching means pre-fetching of data. The data can then be accessed without further cross-process communication. Caching is typically used by UI Automation client applications to retrieve properties and control patterns in bulk. Information is then retrieved from the cache as needed. The application updates the cache periodically, usually in response to events signifying that something in the user interface (UI) has changed.
The benefits of caching are most noticeable with Windows Presentation Foundation (WPF) controls and custom controls that have server-side UI Automation providers. There is less benefit when accessing client-side providers such as the default providers for Win32 controls.
Caching occurs when the application activates a CacheRequest and then uses any method or property that returns an AutomationElement; for example, FindFirst, FindAll. The methods of the TreeWalker class are an exception; caching is only done if a CacheRequest is specified as a parameter (for example, TreeWalker.GetFirstChild(AutomationElement, CacheRequest).
Caching also occurs when you subscribe to an event while a CacheRequest is active. The AutomationElement passed to your event handler as the source of an event contains the cached properties and patterns specified by the original CacheRequest. Any changes made to the CacheRequest after you subscribe to the event have no effect.
The UI Automation properties and control patterns of an element can be cached.
This topic contains the following sections.
The CacheRequest specifies the following options for caching.
Properties to Cache
You can specify properties to cache by calling Add(AutomationProperty) for each property before activating the request.
Control Patterns to Cache
You can specify control patterns to cache by calling Add(AutomationPattern) for each pattern before activating the request. When a pattern is cached, its properties are not automatically cached; you must specify the properties you want cached by using CacheRequest.Add.
Scope and Filtering of Caching
You can specify the elements whose properties and patterns you want to cache by setting the CacheRequest.TreeScope property before activating the request. The scope is relative to the elements that are retrieved while the request is active. For example, if you set only Children, and then retrieve an AutomationElement, the properties and patterns of children of that element are cached, but not those of the element itself. To ensure that caching is done for the retrieved element itself, you must include Element in the TreeScope property. It is not possible to set the scope to Parent or Ancestors. However, a parent element can be cached when a child element is cached; see Retrieving Cached Children and Parents in this topic.
The extent of caching is also affected by the CacheRequest.TreeFilter property. By default, caching is performed only for elements that appear in the control view of the UI Automation tree. However, you can change this property to apply caching to all elements, or only to elements that appear in the content view.
Strength of the Element References
When you retrieve an AutomationElement, by default you have access to all properties and patterns of that element, including those that were not cached. However, for greater efficiency you can specify that the reference to the element refers to cached data only, by setting the AutomationElementMode property of the CacheRequest to None. In this case, you do not have access to any non-cached properties and patterns of retrieved elements. This means that you cannot access any properties through GetCurrentPropertyValue or the Current property of AutomationElement or any control pattern; nor can you retrieve a pattern by using GetCurrentPattern or TryGetCurrentPattern. On cached patterns, you can call methods that retrieve array properties, such as SelectionPattern.SelectionPatternInformation.GetSelection, but not any that perform actions on the control, such as InvokePattern.Invoke.
An example of an application that might not need full references to objects is a screen reader, which would prefetch the Name and ControlType properties of elements in a window but would not need the AutomationElement objects themselves.
The usual way is to call Activate. This method returns an object that implements IDisposable. The request remains active as long as the IDisposable object exists. The easiest way to control the lifetime of the object is to enclose the call within a using (C#) or Using (Visual Basic) block. This ensures that the request will be popped from the stack even if an exception is raised.
Another way, which is useful when you wish to nest cache requests, is to call Push. This puts the request on a stack and activates it. The request remains active until it is removed from the stack by Pop. The request becomes temporarily inactive if another request is pushed onto the stack; only the top request on the stack is active.
You can retrieve the cached properties of an element through the following methods and properties.
An exception is raised if the requested property is not in the cache.
Cached, like Current, exposes individual properties as members of a structure. However, you do not need to retrieve this structure; you can access the individual properties directly. For example, the Name property can be obtained from element.Cached.Name, where element is an AutomationElement.
You can retrieve the cached control patterns of an element through the following methods.
You can retrieve the cached properties of a control pattern by using the Cached property of the pattern object. You can also retrieve the current values through the Current property, but only if None was not specified when the AutomationElement was retrieved. (Full is the default value, and this permits access to the current values.)
When you retrieve an AutomationElement and request caching for children of that element through the TreeScope property of the request, it is subsequently possible to get the child elements from the CachedChildren property of the element you retrieved.
You cannot cache parents or ancestors of the root element of the request.
The cache is valid only as long as nothing changes in the UI. Your application is responsible for updating the cache, typically in response to events.
If you subscribe to an event while a CacheRequest is active, you obtain an AutomationElement with an updated cache as the source of the event whenever your event-handler delegate is called. You can also update cached information for an element by calling GetUpdatedCache. You can pass in the original CacheRequest to update all information that was previously cached.
Updating the cache does not alter the properties of any existing AutomationElement references.