Mike Ormond's Blog

Musings on mobile development and Windows Phone 7 in particular.

Silverlight HtmlElement.Children in IE and FireFox

Silverlight HtmlElement.Children in IE and FireFox

  • Comments 2

In order to demo Silverlight I created a big lump of XAML that allows me to show most of the core capabilities and play around with things like transforms, brushes, storyboards and the like. It's just an easy way to be able to show some of the capabilities of Silverlight. One problem I faced was that the end result was a bit cluttered - we tend to demo at 1024x768 resolution and that doesn't give you much screen real estate to play with. So I thought I'd organise things in a tab control.

Initially I thought of building a Silverlight tab control but I quickly realised that this was going to take more time than I had available so instead I opted for DHTML. Using this excellent article on HTML Dog as a starting point I quickly built a tab control and the JavaScript to make it function and dynamically change the styles on the tabs to give the illusion of tab switching. Of course I also had to write some code to switch my XAML Canvases on and off (each feature I want to show has its own Canvas). As I'm using Silverlight 1.1, that code was written in C#. What an idiot (I thought), why not just move all the HTML stuff into C# too. So I threw away my JavaScript and re-wrote my tab control in C# using the HTML capabilities in Silverlight.

Those capabilities live in the System.Windows.Broswer namespace which has classes such as HtmlPage, HtmlDocument and HtmlElement. A line of C# code such as:

private HtmlElement TabHolder = HtmlPage.Document.GetElementByID("TabHolder");

allows me to grab hold of my "TabHolder" element (you're going to want to see the HTML now aren't you?):

    <ul id="TabHolder">
      <li><a href="#">Primitives</a></li>
      <li><a href="#">Images</a></li>
      <li><a href="#">Brushes</a></li>
      <li><a href="#">Video</a></li>
      <li><a href="#">Animations</a></li>
      <li><a href="#">Complex</a></li>
    </ul>

And I can then access the HtmlElement.Children collection of my TabHolder element to access the <li> elements. I give each of these an ID and hook up an event handler to it (all in C#). A bit like this:

    private void InitialiseTabs()
    {
      int j = 0;

      foreach (HtmlElement li in TabHolder.Children)
      {
        li.ID = "Canvas_" + j++.ToString();
        li.AttachEvent("onclick", new EventHandler(this.HandleTabChange));
      }

This is very cool. I'm now writing all my Silverlight application in C# and it still allows me to access the browser DOM and maniplate elements, respond to events etc. I like this!

Imagine my surprise then when I fired up my application in FireFox and instead of looking like this:

image

 Instead it looked like this:

image

and all the tab functionality was broken.

I fired up the debugger and 100% failed to get any breakpoints to hit in FireFox. For the record this was 100% my own fault. Anyway, it's pretty easy to get this working:

  • Set a breakpoint in your managed code
  • Fire up the application in FireFox (easiest thing I find to do is right-click on the page you want and select "Browse with..." then select FireFox
  • In VS, select "Debug -> Attach to Process"
  • Make sure the "Attach To" code type is set to automatic
  • Attach to the relevant FireFox instance
  • As my breakpoint was in the Load handler, I had to reload the page in FireFox. This is where my problems started because for whatever reason, F5 wasn't reloading the page so my breakpoints weren't being hit. But not to worry, that's sorted out now.. :-)

TabHolder.Children.Count was 6 in IE (and hence worked) but 13 in FireFox (this broke various things including using the tab number as an index into the Children collection). What's happening is that FireFox treats whitespace in the source HTML as an element so you get extra text elements in the DOM if you format your HTML source the way I have.

One option is to reformat your source (not elegant). I preferred to add a check in my foreach to ensure the HtmlElement was a <li> before setting the ID and attaching the event handler. Trouble is I couldn't find a good way to do this. In the end I used the Children.Count property as my <li> elements have an <a> child. If you try to use the TagName property, an exception will be thrown for the text elements.

Having sorted that out, it all works a treat. You can even take a look at it if you're interested. As part of the demo I change various properties of the elements such as transforms, brushes etc so you can see the full range of effects but you get the general idea.

Technorati tags:
Page 1 of 1 (2 items)