0

I'm trying to use automation to find a tree item in an instance of a WinForms FolderBrowserDialog I show the dialog in one process and then call the following in another test process:

var dlg = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Browse For Folder"));
var treectrl = dlg.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "SHBrowseForFolder ShellNameSpace Control"));
var treeview = treectrl.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "SysTreeView32"));
var item = treeCtrl.FindFirst(TreeScope.Descendants, new AndCondition(
    new PropertyCondition(AutomationElement.NameProperty, "Desktop"),
    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TreeItem)));

dlg, treectrl, and treeview come back with valid AutomationElements but item ends up being null even though, when I use the Inspect app, it shows that item with the name "Desktop" as an immediate child of the treeview.

When I tried to use a TreeWalker to walk through the tree control children, all I see are the scrollbar and its children.

Is there something else I need to do to be able to find tree items in a shell tree control?

cppguy
  • 3,611
  • 2
  • 21
  • 36
  • I suggest to change the initial condition to `var dlg = AutomationElement.RootElement.FindAll(TreeScope.Subtree, new PropertyCondition(AutomationElement.ClassNameProperty, "#32770"));`, then check whether the Name is `Browse For Folder`. Avoid in this case an `AndCondition` that includes the NameProperty of a Dialog in the Descendant or SubTree scope. You cannot use `TreeScope.Children`, the Dialog belongs to an app process. You can skip `treectrl`, treeview is `dlg.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ClassNameProperty, "SysTreeView32"));`. – Jimi Oct 15 '20 at 20:29
  • After that, `var item = treeview.FindFirst(TreeScope.Children, new AndCondition(...)`. It would be better if instead of `RootElement` you could specify the AutomationElement derived from a defined Window handle. -- You can also use the WindowPattern.WindowOpenedEvent to be notified when a Window of a specific class is opened and the WindowPattern.WindowClosedEvent to be notified when it's closed. – Jimi Oct 15 '20 at 20:36
  • @jimi thanks for the tips. This is just a minimal piece of code for the purposes of the question. It's not actually how my code is structured. Curious what you mean by "You cannot use TreeScope.Children, the Dialog belongs to an app process". That currently works for me as stated above. Is that what is affecting my subsequent treeitem query? – cppguy Oct 15 '20 at 21:15
  • If the Dialog is opened by an app's Window, the Dialog belongs to the app's Process, it's not part of the Children tree of the RootElement (the Desktop), but you can find it in the SubTree (all Children and Descendants). It's a wide search though, it's usually avoided. If what you're showing is not your code, then you maybe don't use the RootElement as the base of the search. Anyway, when `dlg` is valid, then the rest is the same. As mentioned, use the ClassName, not the (localized) NameProperty (the Text), you may raise COM exceptions, quite probable outcome when RootElement is the base. – Jimi Oct 15 '20 at 21:25
  • 1
    I recall it is not easy to work with `TreeView` objects. I posted a couple of times about them. These might help you out: [TreeScope.Subtree](https://stackoverflow.com/questions/1173808/can-i-copy-multiple-rows-from-the-visual-studio-find-symbol-results-window) and [TVM_GETITEM](https://stackoverflow.com/questions/27682170/sendmessage-treeview-tvm-getitem-crashes-that-process) – Loathing Oct 17 '20 at 04:10

0 Answers0