The blog of dlaa.me

"Those who cannot remember the past are condemned to repeat it." [WebBrowserExtensions.StringSource attached dependency property makes Silverlight/Windows Phone/WPF's WebBrowser control more XAML- and binding-friendly]

The WebBrowser control is available in Silverlight 4, Windows Phone 7, and all versions of WPF. It's mostly the same everywhere, though there are some specific differences to keep in mind when using it on Silverlight-based platforms. WebBrowser offers two ways to provide its content: by passing a URI or by passing a string with HTML text:

  1. If you have a URI, you can set the Source (dependency) property in code or XAML or you can call the Navigate(Uri) method from code.

    Aside: It's not clear to me what the Navigate(Uri) method enables that the Source property doesn't, but flexibility is nice, so I won't dwell on this. :)
  2. On the other hand, if you have a string, your only option is to call the NavigateToString(string) method from code.

    XAML and data-binding support for strings? Nope, not so much...

 

I'm not sure why all three platforms have the same limitation, but I suspect there was a good reason at some point in time and maybe nobody has revisited the decision since then. Be that as it may, the brief research I did before writing this post suggests that a good number of people have been inconvenienced by the issue. Therefore, I've written a simple attached dependency property to add support for providing HTML strings in XAML via data binding!

<phone:WebBrowser delay:WebBrowserExtensions.StringSource="{Binding MyProperty}"/>

As you can see above, this functionality is made possible by the StringSource property which is exposed by the WebBrowserExtensions class. It's a fairly simple attached property that just passes its new value on to the WebBrowser's NavigateToString method to do the real work. For everyone's convenience, I've tried to make sure my StringSource implementation works on Silverlight 4, Windows Phone 7, and WPF.

Aside: The StringSource property is read/write from code and XAML, but does not attempt to detect WebBrowser navigation by other means (and somehow "transform" the results into a corresponding HTML string). Therefore, if you're interleaving multiple navigation methods in the same application, reading from StringSource may not be correct - but writing to it should always work!

Aside: Things are more complicated on Windows Phone because the WebBrowser implementation there throws exceptions if it gets touched outside the visual tree. Therefore, if WINDOWS_PHONE is defined (and by default it is for phone projects), this code catches the possible InvalidOperationException and deals with it by creating a handler for the WebBrowser's Loaded event that attempts to re-set the string once the control is known to be in the visual tree. If the second attempt fails, the exception is allowed to bubble out of the method. This seems to work nicely for the typical "string in XAML" scenario, though it's possible more complex scenarios will require a more involved workaround.

My thanks go out to Roger Guess for trying an early version of the code and reminding me of this gotcha!

 

To prove to ourselves that StringSource behaves as we intend, let's create the world's simplest RSS reader! All it will do is download a single RSS feed, parse it for the titles and content of each post, and display those titles in a ListBox. There'll be a WebBrowser control using StringSource to bind to the ListBox's SelectedItem property (all XAML; no code!), so that when a title is clicked, its content will automatically be displayed by the WebBrowser!

 

Here's what it looks like on Silverlight (note that the sample must be run outside the browser because of network security access restrictions in Silverlight):

WebBrowserExtensions on Silverlight

 

And here's the same code running on Windows Phone:

WebBrowserExtensions on Windows Phone

 

And on WPF:

WebBrowserExtensions on WPF

 

[Click here to download the WebBrowserExtensions class and the samples above for Silverlight, Windows Phone, and WPF.]

 

The StringSource attached dependency property is simple code for a simple purpose. It doesn't have a lot of bells and whistles, but it gets the job done nicely and fills a small gap in the platform. You won't always deal with HTML content directly, but when you do, StringSource makes it easy to combine the WebBrowser control with XAML and data binding!