http://www.automationspy.com/post-25_12_2014.html
Get all control children of an element using AutomationElement.FindAll function:
1 // using FindAll function 2 private List<AutomationElement> GetChildren(AutomationElement parent) 3 { 4 if (parent == null) 5 { 6 // null parameter 7 throw new ArgumentException(); 8 } 9 AutomationElementCollection collection = parent.FindAll(TreeScope.Children, Condition.TrueCondition); 10 if (collection != null) 11 { 12 List<AutomationElement> result = new List<AutomationElement>(collection.Cast<AutomationElement>()); 13 return result; 14 } 15 else 16 { 17 // some error occured 18 return null; 19 } 20 }
Get control children of an element using the predefined TreeWalker.ControlViewWalker:
// using predefined TreeWalker.ControlViewWalker private List<AutomationElement> GetChildren(AutomationElement parent) { if (parent == null) { // null parameter throw new ArgumentException(); } List<AutomationElement> result = new List<AutomationElement>(); // the predefined tree walker wich iterates through controls TreeWalker tw = TreeWalker.ControlViewWalker; AutomationElement child = tw.GetFirstChild(parent); while (child != null) { result.Add(child); child = tw.GetNextSibling(child); } return result; }
Get the same result using a custom TreeWalker:
1 // using customized TreeWalker 2 private List<AutomationElement> GetChildren(AutomationElement parent) 3 { 4 if (parent == null) 5 { 6 throw new ArgumentException(); 7 } 8 List<AutomationElement> result = new List<AutomationElement>(); 9 PropertyCondition condition = new PropertyCondition(AutomationElement.IsControlElementProperty, true); 10 TreeWalker tw = new TreeWalker(condition); 11 AutomationElement child = tw.GetFirstChild(parent); 12 while (child != null) 13 { 14 result.Add(child); 15 child = tw.GetNextSibling(child); 16 } 17 return result; 18 }
MS UI Automation has two ways of navigating through collections of elements and hierarchies. One is by using FindAll function and can be used to obtain the entire collection or a subset of children/descendants of an Automation Element and the second way is by using TreeWalker. Both ways support search filtering by element properties. TW offers a lot more search features and navigation features like moving to first child, moving to last child, moving to next sibling of a specified element and moving to Parent.
What is the connection between TreeWalker and FindAll function? FindAll is the same with using the predefined tree walker TW.ControlViewWalker and moving from the first child to the last child. So, FindAll function returns only control elements.
There are 2 other predefined tree walkers: RawViewWalker and ContentViewWalker. RawViewWalker gets all the elements and ContentViewWalker gets elements marked as content elements.
If you are using a similarity between TW.RawViewWalker or TW.ContentViewWalker and FindAll function you may find some incompatibilities meaning that you may find some Automation elements in one collection that don‘t have correspondents in the other collection. I think FindAll function can be used safely with TW.ControlViewWalker as 1-1.
Why to use FindAll and why to use TreeWalker or why not always to use TreeWalker? Microsoft says FindAll function works faster than TreeWalker for some kinds of applications, like WPF applications, and TreeWalker works faster for Win32 controls. Could be, but the difference of speed may not be so big as you expect. FindAll function has also the advantage of making things easy when you want to search through the entire collection of descendants. TreeWalker can also be used to search through the collection of descendants (recursively), but with more code and less efficiency.
Working with UI Automation may be challenging when using large collections of children or descendants and especially when using filtering criteria because these kinds of actions can be very time-consuming. So, understanding how to work with collections and navigating through hierarchies of elements is a big step in starting development with Microsoft UI Automation.