Automation of ListBoxes with DataItemTemplates - HowTo?

Oct 20, 2010 at 5:25 PM

As a followup to the discussion here:

http://social.msdn.microsoft.com/Forums/en-US/vsautotest/thread/fcb21b5e-8797-4d1d-92fa-3ad4aa945d51?prof=required

It does not appear that anyone has been able to successfully accomplish this.  I am cross-posting here to see of anyone on the white discussion board knows how to access information in any other DataItemTemplate within a listbox because from the first item. 

We have modifed the TextBlock to be automation-friendly as follows:

    public class AutomatableTextBlock : TextBlock
    {
        protected override AutomationPeer OnCreateAutomationPeer()
        {
            return new AutomatableTextBlockAutomationPeer(this);
        }

        class AutomatableTextBlockAutomationPeer : TextBlockAutomationPeer
        {
            public AutomatableTextBlockAutomationPeer(TextBlock owner)
                : base(owner)
            { }

            protected override bool IsControlElementCore()
            { return true; }
        }
    }

 

And here is a snippet of code that I am using to try to access information in the ListBox...

In my case, when I get the control, regardless of what is selected in the list box, it is always the first row's control.  It seems like I should be able to get the TextBlock (as modifed above for automation purposes) from the theList.SelectedItem, but I sure cannot seem to figure out how to do that.

Here is what my code looks like:

=-=-

White.Core.UIItems.ListBoxItems.ListBox theList = wnd.Get<White.Core.UIItems.ListBoxItems.ListBox>("theList");

theList.Select(1);

Label selectedItemNameLabel1 = wnd.Get<Label>("PartNumber");

string strPartNumber1 = selectedItemNameLabel1.Text;

string strPartNumber2 = selectedItemNameLabel1.Name;

theList.Select(3);

Label selectedItemNameLabel2 = wnd.Get<Label>("PartNumber");

string strPartNumber1b = selectedItemNameLabel2.Text;

string strPartNumber2b = selectedItemNameLabel2.Name;

Oct 21, 2010 at 11:08 AM

Hi

what is the problem ?

Does UISpy /UIVerify now see the Label? (after using the extended TextBlock)

is the label a direct children of the window, or in a deeper layer? (best way is to follow the layer down, and don't get the elements from the highest element, because of performance)

in some cases this would help

 

AutomationElement element = wnd.GetElement(SearchCriteria.ByAutomationId("id"));

Label label = new Label (element, wnd.ActionListener);

 

Throndorin

 

 

Oct 21, 2010 at 6:25 PM

Snoop sees all of the controls and their values.

The label we are looking for is inside a data template used as a ListBox ListItem.

Regardless, the first listbox item that is visible is only ever returned.

Searching by Id always returns the first visible label, from the first visible data-templated listbox item.  I need to be able to retrieve values from listbox items (that have data templates) that are not the first visible item on the screen.

Oct 22, 2010 at 8:22 AM

Hi

than you should get the label directly from the listitem.

That snoop show you the elemnts does not mean that they are visible for UIAutomation, Snoop shows the visual tree and not all elements from the visual tree are visible for UIAutomation.

So lets come back to your problem.

I understand this

 

ListBox

   listitem

     label

   listitem

     label

     ....

 

is this the struture UIAVerify see?

 

Throndorin

 

 

Oct 22, 2010 at 3:29 PM

It is, however, I cannot seem to figure out how to make that happen through code.

Oct 23, 2010 at 11:38 PM

Hi

your result is correct. the Get method always return the first found element with this search criteria.

ok try this:

 

 

public Label GetLabelFromListBoxItem(ListBox box, string idOrName, bool isID)
{
  ListItem item = null;

  if(isID)
  {
    item = box.Items.Where(p=>p.AutomationElement.Current.AutomationID == idOrName).First();
  }
  else
  {
    item = box.Items.Where(p=>p.Name == idOrName).First();
  }

  AutomationElement element = item.GetElement(SearchCriteria.ByAutomationId("PartNumber"));

  if(element!= null
  {
    return new Label(element, item.ActionListener);
  }
  else
  {
    return null;
  }
}

 

maybe you can use item.Get<Label>, but mostly the result is null, so the above solution is better.

 

Throndorin