2

I'm working with application window containing a lot of log messages. I need to filter them and retrieve those only that mathches some condition. My choice to traverse them all is TreeWalker as filtering full bulk of messages after AutomationElement.GetAll() is too expensive (there might be thousands of messages).

    List<AutomationElement> messages = new List<AutomationElement>();
    TreeWalker walker = new TreeWalker(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.DataItem));
    AutomationElement row = walker.GetFirstChild(parentDatagrid);
    while (row != null)
    {
        if (/*some condition*/)
            messages.Add(row);
        row = walker.GetNextSibling(row);
    }

Here is the UISpy view of control hierarchy I'm testing.

Screenshot from UISpy

Unexpectedly messages length is larger that actual log messages count. I queried for extra automation elements is UISpy and found that this elements were retrieved from another window (they also matched the condition ControlTypeProperty = ControlType.DataItem). Moreover, this window belonged even to another application. TreeWalker finished its search in the scope of parentDatagrid and continued to traverse all desktop hierarchy.

Of course, I hoped to get only child elements of datagrid. What could cause such strange TreeWalker behaviour? Maybe, my code is wrong, but I wrote the same snipped multiple times, and it worked correctly.

Grade
  • 574
  • 1
  • 5
  • 16

2 Answers2

1

In fact I can't tell you why TreeWalker does that, because I never use TreeWalker for navigation. I just use it for looking up parents, childs, sibilings, etc..

What I can tell you is, that I have very good experience using the following:

List<AutomationElement> messages = new List<AutomationElement>();
AutomationElement parentDatagrid;//your AE

Condition yourCond = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.DataItem));
AutomationElementCollection aECollection;
aECollection= parentDatagrid.FindAll(TreeScope.Element | TreeScope.Descendants, yourCond);
foreach (AutomationElement element in aECollection)
{
    //whatever you like
}

of course you have to be careful with TreeScope.Descendants, if performance is an issue. Then you should might consider TreeScope.Children instead, since Descendants looks at all subelements and Children just at the direct childs.

hope this helps!

Haphil
  • 1,180
  • 1
  • 14
  • 33
  • Thanks for your reply. TreeWalker is intentionally used for navigation here because it allows to traverse controls one by one without pre-loading all of them as AutomationElement.FindAll() does. – Grade Mar 31 '14 at 16:12
  • just to make sure: have you also tried it with TreeScope.Children instead of TreeScope.Descendants? I tested an example app, with some hierarchies (around 30) and in total around 250 elements, and it took me around 0,3-0,6 sec for each element, with TreeScope.Children it was a lot faster (around 0,01-0,001) – Haphil Mar 31 '14 at 16:24
  • in case you are automating wpf controls read the following [msdn-link](http://msdn.microsoft.com/en-us/library/ms788741(v=vs.110).aspx) otherwise I am sorry... "The following example shows two ways of retrieving a specified item from a list, one using TreeWalker and the other using FindAll. The first technique tends to be faster for Win32 controls, but the second is faster for Windows Presentation Foundation (WPF) controls." – Haphil Apr 01 '14 at 07:19
0

When you create a custom TreeWalker, like you did, the behavior will be as you mentioned. It may be better you use a TreeWalker.ControlViewWalker and then check each of the retrieved elements for your condition.

DoronG
  • 2,576
  • 16
  • 22