8088 Views // 0 Comments // 3.0 Rating

Silverlight IsWindowless-ness, And How You Don’t Need It To Display Flash!

Now, a lot has been written about Silverlight interop with regard Flash, not to mention HTML, JavaScript, WCF, and even other Silverlight controls. Like my last few postings on the topic, I want to call out that even though there's much blogging that's been done on this topic, I've stumbled onto an ancillary scenario seemingly along the same lines as others. However, it's distinct enough to be worth mentioning; distinct enough to not be yet another of the same thing as the previous six links you probably just glazed over on Bing or Google.

When you consider a browser with plugins (specifically plugins that are part of the content, verses "add-ins" which are tools that may or may not interact with the content, but are definitely not part of it [Silverlight is a plugin, FireBug is an add-in]) there are two dimensions at play when it comes to physically rendering the page. First there's the HTML, and second there's the plugin. And generally, they stay separate. FireFox, for example, goes so far as to run its plugins in a different process.

I use the word "dimension" specifically in the preceding paragraph. HTML is in one dimension, and Silverlight or Flash or Java is in another. Even though plugins appear to be embedded within the HTML, they really aren't part of it at all. The browser tells the plugin where it will be displayed, and the plugin does the rest: its own execution, app domain management, rendering, etc. Despite the HTML bridge that exists in Silverlight, plugins and HTML are not aware of each other. In fact, that's why such a bridge exists at all.

To continue this spatial metaphor, each dimension has its own Z-indexing system, much like the axes of the Cartesian plane. The Z-index of a div has no bearing on the Z-index of a Canvas. I've seen people in the forums making this mistake time and again. There is no magical combination of Z-Indexes of div tags, object tags, or Silverlight controls that will, for example, allow you to have a long Silverlight ComboBox hang below its object tag's content region and superimpose itself over the surrounding HTML. Not possible. That would be like simultaneously standing on both sides of a wall with no doorway or threshold.

The confusion deepens with Silverlight's introduction of the IsWindowless property into the mix. This is probably the least understood (or most misunderstood) Silverlight concept. Some seem to regard this as a panacea for Silverlight oddities. Does your non-rectangular control have a weird black background? Set IsWindowless to true. Can't get HTML to show up on top of Silverlight? Set IsWindowless to true. Those who have been through the trenches know that there's a performance hit to IsWindowless-ness, but it's hard to stop at that when this magical Boolean makes your bizarre issues go away.

What's really happening is that IsWindowless acts like an interdimensional worm hole between the HTML and Silverlight worlds. Even though the dimensions stay separate, IsWindowless forces Silverlight to do the diligence of rendering itself as though the worlds could be combined. I assume this is where the extra work comes in causing the much-warned-against performance ramifications. But it still doesn't inject itself into the HTML Z-indexing scheme. Now, that said, the div that the object tag lives will be rendered in the specified Z order, as in the following example:

A div with a Z-index of 2 will be rendered beneath a div with a Z-index of 3 that contains Silverlight content. A div with a Z-index of 4 (and the proper absolute positioning) will be rendered topmost.

However, any Silverlight Z-indexes will stay in their own dimension. So although you can now have HTML on top of Silverlight, you still can't shuffle Canvases and divs together. But at least we can get this multidimensional beast of a webpage acting as though its constituent parts were cohesively working together to render unified content.

But this worm hole can lead us to more harm than good. For example, such blending of HTML and Silverlight breaks drag & drop. Since Silverlight now lives "within-ish" the HTML, it stops receiving its own mouse events, as the browser intercepts them. Our application depended on drag & drop, so IsWindowless was out, as was our requirement to be able to display Flash videos over our Silverlight control.

So that brings me to the point: you can still superimpose Flash over Silverlight without the crutch (and ensuing sluggishness) of IsWindowless.

In both HTML and Silverlight, any ties between two elements with the same Z-index values would be broken by the order in which they were added to their parent container. For example, if two TextBlocks were added to a Canvas in xaml and had no Z-indexes set, both values would default to zero, the the TextBlock add last would display over top the of the first one. What if this principle guided the Z-index ordering of plugins as it did elements?

When I had IsWindowless turned on, an absolutely-positioned div I created dynamically via a Silverlight button click (and is therefore added to the DOM after the Silverlight) would position itself correctly topmost on the page with the proper Z-index. When I turned IsWindowless off, the div, as expected, disappeared. Upon inspecting the page with FireBug, out wayward div was indeed still there, just loitering in the wrong dimension!

Now what if this div contained the Flash content (by way of an HTML object tag)? Even though the div wouldn't be displayed, since the Flash plugin was technically added to the DOM after Silverlight's, it should still show up, on top of the app, positioned according to its div. And guess what: it worked! Well, almost; IE needed some coaxing. Here's the JavaScript that worked cross-browser.

Code Listing 1

  1. var _div;
  2. function ShowVideo(html, width, height)
  3. {
  4. //get middle x and y
  5. var x = ($(window).width() / 2) - (width / 2);
  6. var y = ($(window).height() / 2) - ((Number(height) - 30) / 2);
  7. //show div
  8. _div = $("#divVideo");
  9. _div.css({ "height": height, "width": width, "top": y, "left": x });
  10. _div.html(html);
  11. //set timeout fixes an ie issue
  12. setTimeout("_div.show();", 100);
  13. }
  14. function HideVideo()
  15. {
  16. //kill flash
  17. var div = $("#divVideo");
  18. div.hide();
  19. div.html("");
  20. }

In Line #2, we're pulling a chunk of HTML out of the database with the object tag all ready to go, along with the height and width of the video, and passing those to the JavaScript method via Silverlight. (How you can easily get these wonderful values with nothing more than a URL to a YouTube clip will be the topic of a future post.)

Line #6 is an adjustment for some Silverlight chrome we display around where the div will show up. We animate a popup with a close button, and then fire the JavaScript that creates the Flash content. The video displays perfectly in the middle of the popup, giving no indication of how many technologies had to be entangled to get it to work. The close button calls "HideVideo" in Line #14.

Line #12 is the fix for IE wonkiness. Basically, nothing would happen when the popup first showed. However, merely clicking on the page would immediately bring the Flash content into position. It was as though IE needed to be kicked like a stubborn horse to recalculate the Z-indexes of the plugins. This is indeed a hack, but it's worked for weeks now. My hunch is that the slower JavaScript engine on IE is to blame. By showing the div, pausing, and then populating it with Flash, it had time to catch up.

Chrome is now my primary browser. Don't tell Microsoft.

But like I said, it works, without having to resort to IsWindowless-ness. Calling HideVideo() in Line #14 properly "disposes" of the Flash by wiping it off the DOM, which will stop playing the current movie before closing it.

That's it! Have fun Flashing your Silverlight!

1 Tag

No Files

No Thoughts

Your Thoughts?

You need to login with Twitter to share a Thought on this post.