Getting multiple objects

Dec 7, 2009 at 3:16 PM

If I do a Window.Items then it returns a complete list of all the items - but as UIItems.  This takes about two seconds with my current app.  If I then want each item as its correct type then I have to do a separate Window.Get<UIItemType>() - which also takes about two seconds per item.

As I already have the AutomationID for that type (and, indeed, a UIItem of it) would there not be a quick way of converting that into a UIItem of the correct type?



Dec 9, 2009 at 12:05 PM

You should not be getting UIItem, you should be getting the correct type. Can you provide some code which illustrates this.

Dec 9, 2009 at 9:25 PM

That's my point.  If I do:

Button button1 = window.Get<Button>("Button1");

Button button2 = window.Get<Button>("Button2");


then each call takes a couple of seconds.  If there are 20-30 items on a page (which there sometimes are) then this is incredibly slow.

window.Items returns all of the items on the page in about 2 seconds.  But they each come back as a UIItem, which means that I can't do anything useful with them.  If I could just grab the whole list, and then do a conversion from a UIItem to a Button (for instance) then this would be staggeringly faster.

What I'd like to do is:

collection = window.Items;

Button button1 = window.Get<Button>(collection["Button1"]); which would take the AutomationID that had already been retrieved and use it to create a UIItems.Button without having to make another UIAutomation call (which seems to be the slow bit).

Does that make sense?

Dec 10, 2009 at 4:44 AM

Yes it does. What you should do is....


var collection = window.Items;
Button button1 = window.Items.Find(item => item.Id == "Button1");
This would be a find in the collection.


Dec 10, 2009 at 7:51 AM

window.Items.Find() returns an IUIItem, not a Button.  How would I get that item as a button?

Dec 10, 2009 at 9:33 AM

I had a play about with the White code to see if I could get something like this working.

I ended up with:

private static T GetControl<T>(Window window,UIItemCollection collection, string controlName) where T : IUIItem
    var uiItem = collection.Find(item => item.PrimaryIdentification == controlName);
    var createdItem = factory.Create(uiItem.AutomationElement, window, typeof(T));
    var finalItem = (T)UIItemProxyFactory.Create(createdItem, window);
    return finalItem;

I had to make "HandleIfCustionUIItem" and "HandleIfUIItemContainer" public to do this, but it seems to work perfectly.

I did some basic timings, and found that, with a form with 30 controls on it, window.Get was taking 900-1100ms to retrieve an item, whereas this was only taking 125-200ms to return a control.  This means that retrieving every item in the current manner would take 30 seconds, vs 6 seconds in the new manner.

All I did was trace the execution and work out which calls were being made.  I'm sure that someone who understands more of the internals of White would be able to make it even faster.

Any thoughts?


Dec 11, 2009 at 4:50 AM

>> window.Items.Find() returns an IUIItem, not a Button.  How would I get that item as a button?

This is not expected behaviour, I run my unit tests for Items and it returns UIItemCollection, which has IUIItem but they can be downcasted to Button, etc (depending on what they are)

Dec 11, 2009 at 8:46 AM

Sorry, my mistake.  It works fine for the base types - but most of our types are custom ones, so I get back a "Panel" or a "Groupbox" rather than what I need.

Any ideas on how I can work around that?

Dec 11, 2009 at 11:31 AM

Having looked more closely - it seems that adding my own type definitions to the ControlDictionary would work - but the DictionaryMappedItemFactory keeps the items private, and even if I do put them in with reflection it doesn't work, because the control finds "panel" instead.

I seem incredibly close to having a fantastic solution here, if I can just bridge this last gap!

Dec 12, 2009 at 6:46 AM

I think it is an issue that you have found, the Items method doesn't understand CustomUIItems.

I am curious about knowing why you are not using the window.Get method(s) instead?

Dec 12, 2009 at 6:55 AM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.