"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:
-
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 theSource
property doesn't, but flexibility is nice, so I won't dwell on this.:) -
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: TheStringSource
property is read/write from code and XAML, but does not attempt to detectWebBrowser
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 fromStringSource
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, ifWINDOWS_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 theWebBrowser
'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):
And here's the same code running on Windows Phone:
And on 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!