Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FindAllDescendants does not return all descendants #614

Open
urielginsburg opened this issue Jan 30, 2024 · 8 comments
Open

FindAllDescendants does not return all descendants #614

urielginsburg opened this issue Jan 30, 2024 · 8 comments

Comments

@urielginsburg
Copy link

Describe the bug
Intermittently, calling FindAllDescendants() for our application's window returns a very partial list. For example, there is a text element, inside a Pane in the window which in not printed out with the rest of the elements.
When the bug reproduces, FlaUIInspect (using latest at this time, 1.3.0) shows the parent Pane element as not expandable.

Code snippets

using (var uia = new UIA3Automation())
{
  var desktop = uia.GetDesktop();
  var propertyLibrary = new UIA3PropertyLibrary();
  var cf = new ConditionFactory(propertyLibrary);
  var window = desktop.FindFirstChild(cf.ByName("<our application's window name>"));
  var allDescendants = window.FindAllDescendants();
  foreach (var d in allDescendants)
    Console.WriteLine($"found descendant {d}");
}

Screenshots

  • When working properly, FlaUIInspect shows this for the text element I am searching for:
working_text_element

And shows this for the parent pane element:
working - pane

  • When the bug reproduces, FlaUIInspect shows this:
not working

Additional context

Wow, I have been at it for DAYS. I tried everything I could think of including:

  • Calling new UIA3Automation().GetDesktop().FindFirstChild(), then calling FindAllDescendants() or FindFirstDescendant() with and without conditions in a Retry loop...
  • Implementing FindDescendants on my own, based on calling FindAllChildren recursively...
    It just randomly reproduces.
@urielginsburg
Copy link
Author

So.. some further insights!

  • This reproduces with content added by code-behind, at set intervals, in our application. It is added in this way:
// in UserControl.xaml.cs code behind
UIElement content = GetCustomContent();
this.ScrollViewer.Content = content;
  • This reproduces with the FlaUI inspect tool but NOT with the inspect tool supplied with the Windows SDK.

this leads me to believe this may have something to do with caching?

@louislefevre
Copy link

Perhaps you could experiment by using TreeWalkerFactory to retrieve the elements and see if that works? For example, if you wanted to retrieve the text from the pane, might be something like:

using (var uia = new UIA3Automation())
{
    var desktop = uia.GetDesktop();
    var propertyLibrary = new UIA3PropertyLibrary();
    var cf = new ConditionFactory(propertyLibrary);
    var window = desktop.FindFirstChild(cf.ByName("<our application's window name>"));

    var pane = window.FindByAutomationId("customContent");
    var paneText = uia.TreeWalkerFactory.GetRawViewWalker().GetFirstChild(pane);
    Assert.IsNotNull(paneText);
}

@urielginsburg
Copy link
Author

urielginsburg commented Jan 31, 2024

@louislefevre thanks for your comment! and yup, that works, the following code works:

using (var uia = new UIA3Automation())
{
    var desktop = uia.GetDesktop();
    var propertyLibrary = new UIA3PropertyLibrary();
    var window = desktop.FindFirstChild(cf.ByName("<window name>"));
    var Status_onUpdate = window.FindFirstDescendant("Status_onUpdate");
    var customContent = Status_onUpdate.FindFirstDescendant("customContent");
    TreeWalker(customContent);
}

static void TreeWalker(AutomationElement root, int depth = 0)
{
    string tabs = "";
    for (int i = 0; i < depth; i++)
        tabs += "\t";

     if (depth == 0)
         Console.WriteLine($"tree walking {root}");
     else
         Console.WriteLine($"{tabs}{root}");
     using (var uia = new UIA3Automation())
     {
         var treeWalker = uia.TreeWalkerFactory.GetRawViewWalker();
         var child = treeWalker.GetFirstChild(root);
         while (child != null)
         {
             TreeWalker(child, depth + 1);
             child = treeWalker.GetNextSibling(child);
         }
     }
}

Still, FlaUI inspect tool does not see the children of window > Status_onUpdate > customContent and neither does window.FindAllDescendants(), while the normal inspect tool does. Since the 'customContent' is added at runtime by assigning a UIElement object to the Content property of a ScrollViewer, could this be caching related?

@Roemer
Copy link
Member

Roemer commented Mar 8, 2024

I am not entirely sure but I think inspect.exe does use the treewalker internally whereas FlaUInspect uses the FindChildren methods. If it works with the walker, use that. There are a ton of bugs in Microsofts framework itself so it is totally possible that your specific case only works with walking.

@Chaoses-Ib
Copy link

@yaira2 has encountered a similar problem when using FlaUI with Files.

The target element "CurrentPathGet" can be seen in Inspect:

image

But Files.FindFirstDescendant(cf => cf.ByAutomationId("CurrentPathGet")) returns null, only Files.FindChildAt(2).FindFirstChild(cf => cf.ByAutomationId("CurrentPathGet")) works (files-community/Listary.FileAppPlugin.Files@a710828).

@maxinfet
Copy link
Contributor

I had a similar problem like this in a WPF application I worked on. In Inspect, I would see all the elements, but when I asked for children or descendants, I would get nothing. Finally, on the client side, I started printing information when elements were added to the GUI and when the OnCreateAutomationPeer event handler was hit.

After a couple weeks of debugging I finally put enough write lines in all the events on this very complex form to realize they were reloading all the elements of the GUI so many times the client was timing out on later OnCreateAutomationPeer events and just not handling them.

The reason inspect.exe was working was because the mouse hovering over the controls triggered a gradient shift on some controls, which caused a redraw and the visual tree to be updated, which caused the automation element tree to be reevaluated, and since less was going on so it would not time out.

I know there is not specific information here but I hope that the description of this class of issue might give you some ideas as to what to look for.

@urielginsburg
Copy link
Author

Thanks everybody for your comments, in case this is helpful to anyone - we overcame the issue this way:
Our issue was mainly around listboxes, so we just clicked on where the list items should be. The result was that a list item was selected and the visual tree was updated and fully populated. Voodoo, but... whatever works :)

@maxinfet
Copy link
Contributor

Thanks everybody for your comments, in case this is helpful to anyone - we overcame the issue this way: Our issue was mainly around listboxes, so we just clicked on where the list items should be. The result was that a list item was selected and the visual tree was updated and fully populated. Voodoo, but... whatever works :)

We used a very similar work around before a set of changes which caused even more reloading of controls on the form.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants