Locating Elements in Silverlight and WPF applications
Before you can automate interaction with elements contained in a Silverlight/WPF application, you need to first locate the elements contained within the application. For complex applications, locating elements is probably going to be one of the more time consuming tasks. Testers will need to spend time understanding how to reliably find an element. Silverlight/WPF applications that we studied that rely heavily on control templates and data binding produce quite complex visual trees. Their elements are not easily searchable by Find.ByName() given the different Silverlight and WPF name scopes created, and the duplication of names within those templates.
The Find Strategy - change the 'Strategy' property that controls how the method behaves when searching for an element.
Finding All Elements - return a list of the elements contained in the application.
Scoped Searches - search for a specific element based on its parent.
Finding Elements by XamlFindExpression - search for an element using a FindExpression.
The simplest method of searching is to use the Find.ByName(String name) method or the Find.ByName<TControl>(String name) method. Both methods take a string parameter that specifies the name of the element to locate in the application. The first method returns a FrameworkElement object while the second method returns an object of type T having the specified name. If an element having the specified name does not exist or is not currently visible, or if the found element cannot be cast into type T, the functions will return null ('Nothing' in VB.NET). For example:
FrameworkElement zoomBox = app.FindName("zoomBox"); TextBox searchText = app.FindName<TextBox>("searchText");
Dim zoomBox As FrameworkElement = app.FindName("zoomBox") Dim searchText As TextBox = app.FindName(Of TextBox)("searchText")
You might be asking "How do I know what name to use to find the element I want?" There really are only a few ways to find out:
Refer to the design document of the application. Hopefully the name has been specified.
Ask the developer what the name of a particular element is.
Examine the source code to find the name.
If the above methods are not available to you, you will have to resort to some sort of Silverlight/WPF spy utility such as this one to discover the name.
The Find object offers a rich set of search methods that enable you to not only find elements using their names, but also by their text or type. Combined with type filtering, LINQ, FrameworkElement navigation, and the Find.AllByXXX routines, you get a rich set of routines that enables you to find any framework element in the tree.
All of the common methods for finding an element to operate on are:
|Find.ByName()/Find.ByName<T>||Returns the first element having the specified name.|
|Find.ByText||Returns the first TextBlock that matches the text provided.|
|Find.ByAutomationId||Returns an element having the automation ID you specify.|
|Find.ByType||Returns the first element found of the specified type (e.g. Canvas, DataGrid, Calendar).|
|AlwaysWaitForElementsVisible||In this mode the Find object always waits for the element to exist and for its Visibility property to equal "Visible". The default amount of time it will wait is 5 seconds. This timeout can be changed by modifying the Find.Timeout property before using the Find object. This strategy is the default setting.|
|WhenNotVisibleReturnElementProxy||In this mode an 'Element Proxy' is returned if the element cannot be found right away. An 'Element Proxy' is a lightweight FrameworkElement object that only contains information on how to locate the desired element in the Visual Tree. This is useful when you want to use the SilverlightApp.Wait.ForExists method.|
|WhenNotVisibleReturnNull||In this mode null (Nothing in VB.NET) is returned if the element cannot be found right away.|
|WhenNotVisibleThrowException||In this mode a generic exception is thrown if the element cannot be found right away.|
|Find.AllByName()/Find.AllByName<T>||Find all elements that have a specific name. Allows filtering on a specific control type.|
|Find.AllByText()||Find all TextBlocks that contain a specific text. Use p:text to search for partial text.|
|Find.AllByType()/Find.AllByType<T>||Find all elements of certain type. i.e Button, Grid..etc. Filtering on type is inherit here.|
|Find.AllByAutomationID()/Find.AllByAutomationID<T>||Find all elements that have a specific automation ID. Allows filtering on a specific control type.|