(Lviv community of .NET developers)

Control Templates and UIAutomation

September 12, 2007 23:54 by fors

Off and on I try and use the UIAutomation libraries from .NET 3.0 for a variety of things. Most often it is testing but not always. Since I do more unit testing than anything else I find LogicalTreeHelper, VisualTreeHelper and the AutomationPeer functionality more useful than AutomationElement.
On a recent project we were doing some work on a screen that wasn't particularly easy to get to. It took about 9 clicks. Not that bad but I'm lazy. We were doing a lot of fancy WPF stuff and we really wanted to see things live in the full application context instead of in Blend or just raw xaml. So we would run the app a lot. I got tired of doing the same clicks and occasionally making mistakes just to get the screen to show. So I chose to write a small app that would use UIAutomation to get me to the screen. Seemed simple enough. I've done plenty of work with UIAutomation and I thought it would be easy. Was I in for a suprise.


We had done something clever to a ListBox to get an button to show up at the top of the list box before the items of the list. We had used a control template to get the button in there. Of course there were at least a dozen other ways to do it but that's a different post.
So to start out I did something sane for once and pointed UISpy at the application before I jumped in and started writing code. To my suprise UISpy could not see the button! I tried the Raw view, the content view, custom views, everything. No button.
Then I put some extra code into the application so I could use VisualTreeHelper to see if it could see the button. Sure enough there it was. So what was wrong with UISpy and therefore UIAutomation?
I thought it would be good to try and reproduce the problem in a smaller more isolated way. Then I could be sure it wasn't something else we did. We had a pretty complicated application going so I wanted to reduce the number of variables. I just created a standard WPF application and put this in the cleverly named Window1.xaml

<Window x:Class="WindowsApplication1.Window1"
  xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
  xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
  xmlns:WindowsApplication1="clr-namespace:WindowsApplication1"
  Title="WindowsApplication1" Height="300" Width="300">
  <Grid>
   <Grid.Resources>
    <Style TargetType=
    "{x:Type WindowsApplication1:SpecialListBox}">
     <Setter Property="Template">
      <Setter.Value>
       <ControlTemplate TargetType=
       "{x:Type WindowsApplication1:SpecialListBox}">
        <Grid>
         <Grid.RowDefinitions>
           <RowDefinition/>
           <RowDefinition/>
         </Grid.RowDefinitions>
         <TextBox x:Name="templateTextBox" Grid.Row="0">
          Can you see me now?</TextBox>
         <StackPanel Grid.Row="1">
          <ItemsPresenter/>
         </StackPanel>
        </Grid>
       </ControlTemplate>
      </Setter.Value>
     </Setter>
    </Style>
   </Grid.Resources>
   <WindowsApplication1:SpecialListBox x:Name="specialList">
     <ListBoxItem>one</ListBoxItem>
     <ListBoxItem>two</ListBoxItem>
   </WindowsApplication1:SpecialListBox> 
  </Grid>
</Window>


There is nothing special about SpecialListBox. It is just a class that derives from ListBox and doesn't override anything, yet. There was also no reason that I switched from Button to TextBox in the smaller code base.
I fired that up, pointed UISpy at it and UISpy could not see TextBox from the control template. It showed the two ListBoxItems just fine. I did some poking around and figured it out eventually.
Since this is a WPF app UIAutomation will talk to AutomationPeers exposed by each WPF element's OnCreateAutomationPeer method. AutomationPeer has a GetChildren method that UISpy and other UIAutomation code will use to navigate the control heirarchy. ListBox will return a ListBoxAutomationPeer instance when its OnCreateAutomationPeer method is called. ListBoxAutomationPeer only returns the list items from its GetChildren implementation. So it will never return the textbox I added to the control template because it doesn't know how.
That seems to put us in a situation where we can't ever get to the textbox. We could refactor and not put the TextBox in the ListBox's ControlTemplate and use a different form of composition like a UserControl. But I thought I'd see if I could get UIAutomation to place nice with the ControlTemplate.
The solution I chose to use is to create my own AutomationPeer for the ListBox. I'm already using a class derived from ListBox anyway so overriding OnCreateAutomationPeer to return my own AutomationPeer is pretty easy. For the custom AutomationPeer itself it seems to make sense to start out by deriving from ListBoxAutomationPeer and seeing if GetChildren can be overriden. It can't, but the GetChildrenCore method can, and that is good enough.
All that has to be done is to add a TextBoxAutomationPeer to the list of children and we should be good to go. SpecialListBox ends up looking like this:

public class SpecialListBox : ListBox
{
   protected override AutomationPeer OnCreateAutomationPeer()
   {
     return new SpecialListBoxAutomationPeer(this);
   }
}


The fun bits are in the SpecialListBoxAutomationPeer. I used a helper class from WPFUtilities to help me get at the TextBox. All it does is make VisualTreeHelper a bit easier to use, but under the covers the work is done by VisualTreeHelper.

public class SpecialListBoxAutomationPeer : ListBoxAutomationPeer{
 
public SpecialListBoxAutomationPeer(ListBox owner) : base(owner)
{
}
 
protected override string GetLocalizedControlTypeCore()
{
  return "SpecialListBox";
}
 
protected override List<AutomationPeer> GetChildrenCore()
 {
  TextBox textBox = null;
  DepthFirstVisualTreeIterator iter = 
  new DepthFirstVisualTreeIterator();
  foreach (DependencyObject dependencyObject in iter.GetNodes(Owner))
  {
    FrameworkElement element = dependencyObject as FrameworkElement;
    if (element != null && element is TextBox && 
    element.Name == "templateTextBox")
    {
      textBox = (TextBox)element;
      break;
    }
  }
  List<AutomationPeer> children = base.GetChildrenCore();
  TextBoxAutomationPeer button = new TextBoxAutomationPeer(textBox);
  children.Add(button);
  return children;
 }
}



SpecialListBoxAutomationPeer just finds the TextBox, creates an AutomationPeer for it, gets the children that would normally be returned and adds the TextBoxAutomationPeer to them.

This all ends up being a bit more work than I think should have to be done. It also requires me to change my code. I can't fix this kind of problem after the fact. I still think re-writing this to use a user control is a better solution. That way I don't have to mess with custom AutomationPeers or anything. Still, it was a good learning exercise.

 

From http://miketwo.blogspot.com/2007/07/control-templates-and-uiautomation-dont.html


Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags: , ,
Categories: WinFx
Actions: Permalink | Comments (34) | RSSRSS comment feed

Comments

February 20. 2010 06:21

This is very well written and constructed. Would love to see more like this in the future.

Coupons

March 27. 2010 09:43

I am grateful to you for sharing this post with us. I have been in search of this post and found the post at the right time. I appreciate for your hard work. Feel free to drop by my buy indoor tanning bed review site.

indoor tanning bed

March 28. 2010 11:21

Thanks for taking the time to share this, I really feel strongly about it and love learning more on this topic. If possible, as you gain expertise, would you mind updating your web site with extra info? It really is particularly valuable for me.

Aquamarine Engagement Rings

March 28. 2010 13:56

You've got accomplished a very fine work, I'm impressed by your information, retain up the beneficial perform. I'd adore to know much more.

hp toner cartridges

March 29. 2010 10:34

I know some people with problems opening the page making use of Opera. I reopened it utilizing Firefox and it seems being ok.I feel I see those exact same errors in Opera as properly.Hope that helps.

Aquamarine Engagement Rings

March 29. 2010 13:25

It was a beneficial workout for me to go through your webpage. It definitely stretches the limits with the mind when you go through very good info and make an effort to interpret it properly. I am going to glance up this web site usually on my PC. Thanks for sharing. I am going to also adhere to your RSS feeds. Excellent luck together with your potential webpage creating.

hp inkjet cartridges

April 3. 2010 11:13

Great blog, keeping me from working

Richard

April 6. 2010 12:16

That is certainly some inspirational stuff. In no way knew that opinions might be this varied. Thanks for all the enthusiasm to offer such very helpful info right here.

Modern Engagement Rings

April 8. 2010 14:17

I'm not a lot of a guy who thinks in so deeply about internet design but I think your submit had some valid points in it. Like designers are forced to design stuff for the limited code available and not go beyond it, their innovation is somewhat limited but still I consider Online Style won't die! I agree that Amazon and other some big sites won't have a weblog but now a days it's extremely essential to have some sort of option available so people can quickly communicate their thoughts. I believe Amazon if wants to shift it to that, they can get a customized CMS for themselves.

six pack abs

April 13. 2010 11:19

I have a great sense of humor and I enjoy laughing the silliest of her jokes.

us

April 28. 2010 12:41

This is interesting, post more often!

Ronnie

May 3. 2010 04:44

Creative ideas flourish best in a shop which preserves some spirit of fun. Nobody is in business for fun, but that does not mean there cannot be fun in business.

essay introduction

May 11. 2010 11:18

Wow, I never knew that toner cartrifges printers. That’s pretty interesting...

Toner cartridges

May 13. 2010 12:19

What a super blog about development. For some reason I usually have a problem with this type of information which is very simple for most people to grasp. Maybe it is because I pay too much attention to the little details. In any case it works for me and I am glad I happened on this site. Your style of writing matches the way that I can understand more easily capture the meaning.

Frankie

May 21. 2010 10:54

I have been visiting your blog lately because I am interestedin reading the quality articles that you post. Keep it up!

good thesis statement

May 26. 2010 13:52

thanks for useful post i appreciated your work

art deco engagement rings

May 31. 2010 04:46

Thank you for starting this nice thread. I've been looking information like this.
Thumbs up!

Li

June 15. 2010 07:28

Such an interesting blog, not like the others that I usually see about development!
Can I link to your blog? Would love to see more! Can't wait to read more about development.

chronic fatigue treatment

June 23. 2010 13:32


Great stuff as usual...

Celtic

June 29. 2010 13:04

This kind of a useful blog�wow !!!!!!

Callum Davidson

June 30. 2010 00:10

I have been looking for some details on this topic and thankfully I found your site. Bookmarking it now.

introduction write

July 5. 2010 17:48

The Big 10 Football Nation Forum can be a website exactly where it is possible to talk about just about something in regards to the NCAA Big 10 Football Conference. You might also discuss about a great many other points like other NCAA Football Conferences, other sports activities, every day chit chat, and a great many other topics. There is usually a specific VIP Section in which you could purchase, sell, trade, or have sports bets with other members. http://www.big10footballnation.net/forums/forum.php

big 10 conference

July 7. 2010 08:40

An additional great post, normally cool to study an excellent post on a subject you genuinely care about.

pee-x

July 7. 2010 19:44

Another interesting blog post like always a joy reading

Mira Jones

July 8. 2010 21:24

As anyone understands respect is probably the most significant between people's existence. Only respect one another to obtain along properly and I consider that leaving one's opinion can be a behavior of respect. Do you assume so?

supra shoes

July 9. 2010 00:58

I had to comment about this blog your information about development is great thanks

William

July 10. 2010 21:50

It had been interesting.
You appear really educated inside your field.

Arian Foster

July 14. 2010 23:06

I have been looking for some details on this topic and thankfully I found your site. Bookmarking it now.

vibram fivefingers

July 19. 2010 21:59

Excellent piece, this is very similar to a site that I have. Please check it out sometime and feel free to leave me a comenet on it and tell me what you think. Im always looking for feedback.

Nike Shox NZ

July 20. 2010 07:10

I had a desire to begin my organization, but I didn't earn enough of money to do that. Thank God my close fellow recommended to take the <a href="http://bestfinance-blog.com/topics/credit-loans";>credit loans</a>. So I used the consolidation loans and made real my desire.

JanineParsons32

July 20. 2010 09:21

No bird soars too high, if he soars with his own wings.

payday loans

July 21. 2010 22:11

You are a really wise individual!

Darnell JenkinsMiami

July 23. 2010 21:00

Ultimately, the only power to which man should aspire is that which he exercises over himself.

payday loans

July 26. 2010 17:27

Ambition, like a torrent, never looks back.

cash loans

Add comment


(Will show your Gravatar icon)