Integrated Links and Styling for Windows Phone 7 WebBrowser Control

By | July 5, 2010

The situation: you need to display nicely formatted HTML in your Windows Phone 7 application. You want the formatting of this HTML to match the system theme, and that formatting to respect the user’s theme selections. So, for example, if the user changes their “highlight” theme colour, the links in the HTML should use this colour. You also want links in that HTML to open the full Internet Explorer browser.

Replicating the system theme

Let’s get down to business. What we need is a generated stylesheet that we can apply to our HTML strings so that they are formatted just like the system style. We can leverage the built-in styles to do this. I created a WebBrowserHelper class, and it has a couple of methods to create the style and layout that I need. First we create the HTML head block:

public static string HtmlHeader(double viewportWidth)
 {
 var head = new StringBuilder();

head.Append("<head>");
 head.Append(string.Format(
 "<meta name=\"viewport\" value=\"width={0}\" user-scalable=\"no\">",
 viewportWidth));
 head.Append("<style>");
 head.Append("html { -ms-text-size-adjust:150% }");
 head.Append(string.Format(
 "body {{background:{0};color:{1};font-family:'Segoe WP';font-size:{2}pt;margin:0;padding:0 }}",
 GetBrowserColor("PhoneBackgroundColor"),
 GetBrowserColor("PhoneForegroundColor"),
 (double)Application.Current.Resources["PhoneFontSizeNormal"]));
 head.Append(string.Format(
 "a {{color:{0}}}",
 GetBrowserColor("PhoneAccentColor")));
 head.Append("</style>");
 head.Append(NotifyScript);
 head.Append("</head>");

return head.ToString();
}

You can see we’re using the Segoe WP system font, and accessing some of the resources like PhoneBackgroundColor to make sure this color changes correctly when the phone style changes. Also, we’re using the meta viewport to set tell the browser when to wrap text. You may need to fiddle the -ms-text-size-adjust:150% to get the text size perfect, depending on the width of your WebBrowser Control.

If you’re wondering about the NotifyScript bit, I’ll explain later.

You’ll notice I need to munge the Silverlight colour resources to get a web-format colour out. I drop the alpha channel from the string using this helper method:

private static string GetBrowserColor(string sourceResource)
{
var color = (Color)Application.Current.Resources[sourceResource];
return "#" + color.ToString().Substring(3, 6);
}

The next step is to create the full html document when we just have an html string (e.g. “This is <b>bold</b>”:

public static string WrapHtml(string htmlSubString, double viewportWidth)
{
var html = new StringBuilder();
html.Append("<html>");
html.Append(HtmlHeader(viewportWidth));
html.Append("<body>");
html.Append(htmlSubString);
html.Append("</body>");
html.Append("</html>");
return html.ToString();
}

Now we can use these helper methods to pass our little basic html string to the WebBrowser control and have it rendered perfectly matching the system theme. Somewhere in the Page_Load or similar:

var fullHtml = WebBrowserHelper.WrapHtml(
"My little html string with <b>bold</b> text",
WebBrowser1.ActualWidth);
WebBrowser1.NavigateToString(fullHtml);

Bear in mind that we will need to reload the WebBrowser content when the theme changes. It would be safest to re-call NavigateToString when our app comes back from Obscured or Deactivated, in case the user went off to the settings panel and changed their theme.

Handling links

We have one other problem. If your HTML has links in it, these links will open with in the WebBrowser control when clicked. We need to catch those clicks and use the WebBrowserHelper control to open them in the full mobile Internet Explorer. The solution to this is in two parts: some javascript to catch all links and send them to the WebBrowser’s containing control (window.external.notify); and the event to handle these clicks.

The critical first step is to make sure our WebBrowser control is allowed to run scripts by setting IsScriptEnabled=”True”. If you don’t do this, nothing below will work.

Part one: this script adds an “onClick” event to every single A tag in the document, and sends the link URL as a message to the WebBrowser’s control. It uses a sneaky bit of javascript to find every A tag and add an onclick event that cancels the original hyperlink click.

public static string NotifyScript
{
get
{
return @"<script>
window.onload = function(){
a = document.getElementsByTagName('a');
for(var i=0; i < a.length; i++){
var msg = a[i].href;
a[i].onclick = function() {notify(msg);};
}
}
function notify(msg) {
window.external.Notify(msg);
event.returnValue=false;
return false;
}
</script>";
}
}

Part two: we need to handle the ScriptNotify event of the WebBrowser control, and simply launch the external browser using the URL we have been passed from the HTML’s A tag.

private void WebBrowser1_ScriptNotify(object sender, NotifyEventArgs e)
{
WebBrowser1.Dispatcher.BeginInvoke(
() => WebBrowserHelper.OpenBrowser(e.Value)
);
}
...
public static void OpenBrowser(string url)
{
WebBrowserTask webBrowserTask = new WebBrowserTask { URL = url };
webBrowserTask.Show();
}

So there you have it. Pass an HTML string (with as much HTML formatting as you want: bold, italics, numbered lists – go to town!) to the WrapHtml helper, and you’ll have an integrated, system-formatted WebBrowser control that handles links properly. Nice!

Download sample code.

14 thoughts on “Integrated Links and Styling for Windows Phone 7 WebBrowser Control

  1. Scott

    Good article as always. You know StringBuilder has AppendFormat as a method? Saves injecting string.Format into it each time…

    Reply
    1. Ben Post author

      Oh lovely. Always good to tidy up erroneous method calls. I’ll remember that one.

      Reply
  2. Hector Huerta

    Hi! I found that if I didn’t specified the script language it wouldn’t work for me so I added that to the NotifyScript string and everything worked.

    Thank you!

    Reply
  3. Dave Baker

    Looks like things changed somewhat! Can only get it working with <meta … content= , not with value= just spent several hours releasing phone != emulator when it comes to WebBrowser and scaling, sizing, orientation…

    Reply
  4. Richard Woo

    Hi, nice write-up. It isn’t necessary to do all that for handling links. You can merely set a Navigating event handler, which will trigger before the WebBrowser starts to navigate to a new page. Define this as the handler:

    private void MyWebBrowserControl_Navigating(object sender, NavigatingEventArgs e)
    {
    e.Cancel = true; // cancel navigation in this WebBrowser
    WebBrowserTask browser = new WebBrowserTask();
    browser.URL = e.Uri.AbsoluteUri;
    browser.Show();
    }

    Reply
  5. suyambu vignesh

    Hello ,

    I am in need to display the images stored in isolated storage in webbrowser control .Can any one please explain me.

    Thanks
    Suyambu Vignesh

    Reply
  6. Min Racca

    Hello! I yesterdayfound your page via Yahoo. What a informative blog you have! I appreciate it very much! Thank you for supplying such valuable comment to the entire internet world!

    Reply
  7. Inkog

    I ran into a problem with your injected script on a Mango device. The external.Notify method always returned the last href found. I had to change the the script to not delare the msg var and pass the function ‘this.href’

    var msg = [i].href; // Remove
    a[i].onclick = function() {notify(this.href);};

    Reply
    1. qhawk

      I found the same thing, but instead I used @Richard Woo’s great suggestion which seems much cleaner. Add a navigating handler.

      Reply
  8. Pingback: Windows Phone 7 ???? | DanceCoder

  9. EngDev

    How to inject Java script at run time to web browser Control in windows phone ? As i didn’t know any information about html in web browser as i only displayed it .

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *