Another of the new capabilities that Silverlight 4 brings to the platform is the ability to host HTML content inside a Silverlight control. This support isn’t limited to static HTML content; the content can be interactive and can include script. It can even be Flash content or content that includes other Silverlight controls.

To host HTML content in Silverlight, you can use either a WebBrowser control or an HtmlBrush. One way to display HTML content is to fire up a WebBrowser control and point it to a URL:

<WebBrowser x:Name=”WebBrowserControl” Source=”http://www.bing.com” />

Another way to do it is to call NavigateToString and pass a string of content to the WebBrowser control:

WebBrowserControl.NavigateToString(“<h1>Hello, Silverlight</h1>”);

HTML hosting is not available to in-browser apps (it applies to out-of-browser applications only), and if an OOB lacks elevated permissions, it can only display content that comes from the same domain as the Silverlight application. However, you can use a little trick to display cross-domain content in OOBs that run without elevated permissions—simply pass an IFRAME targeting the remote content to NavigateToString:

WebBrowserControl.NavigateToString(“”);

You can render HTML content with HtmlBrush, too. The following XAML snippet paints a Rectangle with content retrieved from Bing:

<WebBrowser x:Name=”WebBrowserControl” Source=”http://www.bing.com” />

<Rectangle>

  <Rectangle.Fill>

    <HtmlBrush SourceName=”WebBrowserControl” />

  </Rectangle.Fill>

</Rectangle>

One difference between WebBrowser and HtmlBrush is that the former displays “live” content, while the latter does not. Another difference is that HtmlBrush can have transforms applied to it, while WebBrowser cannot. For snazzy visual effects involving HTML content like the HTML puzzle demoed at the PDC, you’ll probably find yourself using HtmlBrush. To display live, interactive content, you’ll find WebBrowser more useful instead.

One of the really cool things about the WebBrowser control is that you can use its InvokeScript method to call JavaScript functions in content hosted by the control. Conversely, JavaScript hosted inside a WebBrowser control can use window.external.Notify to raise ScriptNotify events that can be handled in C#.

To demonstrate why this might be useful (and how it works), I built a sample application that plays YouTube video using YouTube’s API player and that uses the player’s JavaScript API to drive the video playback from C#. The application runs as an OOB and requires elevated permissions:

Silverlight YouTube Application

The video that plays in the application is one I uploaded to YouTube; it shows one of my RC jets getting a workout at a recent jet meet near Atlanta, GA. You can download the app and install it on your PC to try it out. Don’t forget that it has to run outside the browser.

The application uses a WebBrowser control to host the YouTube player. The content is stored in a text file packaged as a loose file inside the XAP file. It’s extracted from the XAP with Application.GetResourceStream and passed to the WebBrowser control via NavigateToString:

// Read the HTML content from the XAP

StreamResourceInfo sri = Application.GetResourceStream

    (new Uri(“YouTubePlayer.txt”, UriKind.Relative));

StreamReader reader = new StreamReader(sri.Stream);

string content = reader.ReadToEnd();

 

// Feed the content to the WebBrowser control

Player.NavigateToString(content);

The content itself includes a mix of HTML and JavaScript (mostly JavaScript). The script instantiates the YouTube player, forwards certain events from the player to the application so they can be handled in C#, and provides a thin JavaScript API layer that the application calls via InvokeScript to control playback of the video. For example, when the user clicks the Play, Pause, and Stop buttons, the application uses InvokeScript to call script funtions named play, pause, stop, and cue:

private void OnPlay(object sender, RoutedEventArgs e)

{

     Player.InvokeScript(“play”);

}

 

private void OnPause(object sender, RoutedEventArgs e)

{

    Player.InvokeScript(“pause”);

}

 

private void OnStop(object sender, RoutedEventArgs e)

{

     Player.InvokeScript(“stop”);

     Player.InvokeScript(“cue”, “df6x4U0u7iQ”);

}

Similarly, when the state of the player changes—for example, when video playback begins or ends—script inside the control uses window.external.Notify to fire a ScriptNotify event in C# and activate a handler that updates the visual states of the buttons:

function onYouTubePlayerStateChange(state) {

    // Ask the Silverlight control to update the YouTube video player

    var state = document.getElementById(“apiplayer”).getPlayerState();

    window.external.Notify(‘Update:’ + state.toString());

} 

The end result is an application that demonstrates key features of the WebBrowser control and does something interesting, too. Merry Christmas and Happy Holidays!