3

I'm using a WPF application that has custom stack panel, which is basically a list. The item in the list is exactly the same so I'm not able to select a specific text to uniquely identify the elements. And some other values such as time are dynamic.

Is there a way for me to get the list of elements returned. I know it's possible because the error was thrown, ElementAmbiguousError state the count.

If I could do that, then from that list I can use the index and validate what I need.

Shubham Jain
  • 16,610
  • 15
  • 78
  • 125
user8678153
  • 93
  • 1
  • 5

2 Answers2

4

You can add found_index=0 or other index to the window specification object. This is the first way to disambiguate the search.

Also there are methods .children() and .descendants() with additional params like control_type or title (as I remember title should work), but some window specification params are not supported in these methods.

Vasily Ryabov
  • 9,386
  • 6
  • 25
  • 78
  • Thanks for your answer Vasily. I have tried your solution, but because of the way the list is created I cannot get the post of children just for the list view. The list view items themselves are children of the main application window. – user8678153 Oct 02 '17 at 16:42
  • It would be very helpful if I could get the count of elements found when I do something like dlg.child_window(auto_id="list_item_name"). This returns the ambiguous error and states the count of elements found. If I could access that count, then it's easy for me to use the found_index property to search through the list – user8678153 Oct 02 '17 at 16:45
  • To enumerate all children use `dlg.children(control_type="ListItem")` or `descendants` method (it lists the whole subtree as a plain list). – Vasily Ryabov Oct 02 '17 at 17:46
  • Thanks for your workaround suggestions. Unfortunately, the way the application is built, the list items display as children of the main application and not under a sub element. So they are just repeated elements in the same level as the other elements. – user8678153 Oct 19 '17 at 15:03
  • OK, then app.windows() should work in this case. It will list all top level windows of the app as a wrappers. – Vasily Ryabov Oct 20 '17 at 05:20
  • I was able to use the error thrown and parse it to get the number of elements. Also was able to use the found_index parameter to select the specific element I need. – user8678153 Jan 10 '18 at 16:38
  • If it resolves your problem, please mark correct answer as accepted (click on grayed check box at the left side of answer). It's considered polite on StackOverflow and motivates others to help you regularly. – Vasily Ryabov Jan 10 '18 at 17:53
1
elements = pywinauto.findwindows.find_elements(<args>)
len(elements)

<args> will need to contain more detailed information than it does when using something like Application().connect(process=<pid>).window().child_window(<args>) because it doesn't have information in the chain about the window in which you're searching. See the documentation on this method for more information.

Also note there is a warning that using this method directly is not recommended as it is a low level API.

Another solution (already provided by vasily) is to parse the error that comes back when multiple elements are found to isolate the number found.

Unless the pywinauto devs decide to provide a higher-level API for accessing the number of elements found, you'll have to weigh the risk of the low-level API changing with the risk of parsing an error message which could also change. I have this problem too and have decided to use find_elements()

  • `.children()` and `.descendants()` methods can accept some of search criteria to filter elements in. Of course, it's not complete now. We thought about providing multiple elements search by `.find_all()/.find_first()` in addition to `.wrapper_object()` (which could be renamed to `.find_one()`). – Vasily Ryabov Mar 25 '18 at 21:04
  • 1
    `.children()` or `.descendants()` would be great to use, but unfortunately I can't give it a `title_re`. I assume regex is not supported for these but haven't checked the source code. I could definitely use `.find_all()`. `.find_first()` seems unnecessary since you can specify `found_index` in selector criteria, yes? – Jeff Arnold Mar 28 '18 at 16:45
  • 1
    Yes, `title_re` is not possible for `children/descendants`. And yes, `found_index` is another legal way to do that. This would just look closer to similar APIs like MS UI Automation, but at a higher level. It's easier to discover `.find_first()` in an IDE tooltip than looking for `found_index` in the docs. – Vasily Ryabov Mar 28 '18 at 17:24
  • @VasilyRyabov How can then we use `find_elements` to search for children by a title regexp? I've posted a question for this https://stackoverflow.com/questions/56873733/how-to-search-children-descendants-by-regular-expression-title-in-pywinauto – Elijas Dapšauskas Jul 03 '19 at 15:44