Coming soon!

Customizing the Windows Phone 8 WebView

I’m currently trying to make my first Windows Phone app (a bit late to the party I know). One of the requirements I have is showing HTML, which I fetch from a REST service, in the app. But this was more challenging than expected. To show HTML I need to use a WebView. But there … Continue reading Customizing the Windows Phone 8 WebView →

  • Mobile development
  • Windows Phone
  • scrollviewer
  • webview

By Thomas Van den Bossche · 9/10/2015 6:27:28 PM (Original Post)

I’m currently trying to make my first Windows Phone app (a bit late to the party I know).
One of the requirements I have is showing HTML, which I fetch from a REST service, in the app.

But this was more challenging than expected.

To show HTML I need to use a WebView.
But there is no databinding support for HTML strings (as far as I know?), the WebView should scale with the content inside it and I should be able to scroll inside my app view (not inside my WebView) so I need a way to disable the scrolling ability in the WebView.

It’s possible that the content of my WebView is larger than the available screen estate but that’s not a problem because I can add a ScrollViewer which allows me to … scroll (tadaa!).

Databinding support for HTML strings

First about the databinding support for HTML strings.
I got this solution from another blog, but unfortunately I forgot which one and can’t find it anymore in my history… I’ll add the author/link once I found it.

The WebView class itself is sealed so I can’t inherit from it.
Another possibility is to register a new attribute for the WebView.

First a look at the code:

public static string GetHtmlContent(WebView view)
{
    return (string)view.GetValue(HtmlContentProperty);
}

public static void SetHtmlContent(WebView view, string value)
{
    view.SetValue(HtmlContentProperty, value);
}

public static readonly DependencyProperty HtmlContentProperty =
    DependencyProperty.RegisterAttached(
        "HtmlContent", 
        typeof(string), 
        typeof(WebViewExtensions),
        new PropertyMetadata(null, OnHtmlContentChanged)
    );

private static void OnHtmlContentChanged(DependencyObject sender,
    DependencyPropertyChangedEventArgs e)
{
    var webView = sender as WebView;
    if (webView == null)
        throw new NotSupportedException();

    if (e.NewValue != null)
    {
        webView.NavigateToString(e.NewValue.ToString());
    }
}

I’ve added this snippet in a static class called WebViewExtensions because additional functionality will be added later on.
You can now easily use the attribute in XAML:

Ok that’s one down.

Resize the WebView according to the content

I used a solution from Jason Poon, but I needed to modify it a little bit to make it work.
The value you get from the JavaScript is in pixels. The unit of the Height property of the WebView is by default in DIP (Device Independent Pixels) which is 1/96th inch according to the documentation of Microsoft.

So before passing the value to the property we need to do a little formula.

var heightString = await webView.InvokeScriptAsync("var height = document.getElementById('content').clientHeight; return height.toString();", new string[0]); 

int height; 
if (int.TryParse(heightString, out height)) {     
    int dipHeight = ((int)(height * 96) / (int)DisplayInformation.GetForCurrentView().RawDpiY);     
    webView.Height = dipHeight; 
}

Because we’re calculating the height we only need the value of the Y-axis.

Unfortunately, we’re not done yet.

When we want to scroll the view we’re still activating the scroll in the WebView.
This is somewhat of a hack, but it seems to work quite well.

The idea is to add a transparent layer on top of the WebView.


    
        
            
                
            
            
        
    

The touch events are now passed on to the Grid which activates the ScrollViewer.

That’s it! Let’s recap with the complete code!

public static class WebViewExtensions
{
  public static async void ResizeToContent(this WebView webView)
  {
      var heightString = await webView.InvokeScriptAsync("var height = document.getElementById('content').clientHeight; return height.toString();", new string[0]); 
      int height;
      if (int.TryParse(heightString, out height))
      {
          int dipHeight = ((int)(height * 96) / (int)DisplayInformation.GetForCurrentView().RawDpiY);
          webView.Height = dipHeight;
      }
  }

  public static string GetHtmlContent(WebView view)
  {
      return (string)view.GetValue(HtmlContentProperty);
  }

  public static void SetHtmlContent(WebView view, string value)
  {
      view.SetValue(HtmlContentProperty, value);
  }

  public static readonly DependencyProperty HtmlContentProperty =
      DependencyProperty.RegisterAttached(
      "HtmlContent", typeof(string), typeof(WebViewExtensions),
      new PropertyMetadata(null, OnHtmlContentChanged));

  private static void OnHtmlContentChanged(DependencyObject sender,
      DependencyPropertyChangedEventArgs e)
  {
      var webView = sender as WebView;
      if (webView == null)
          throw new NotSupportedException();

      if (e.NewValue != null)
      {
          webView.NavigateToString(e.NewValue.ToString());
      }
  }
}

It feels somewhat like applying different hacks together but it seems to work quite well!


  • Mobile development
  • Windows Phone
  • scrollviewer
  • webview

By Thomas Van den Bossche · 9/10/2015 6:27:28 PM (Original Post)

Share this blogpost

Looking for talent?

Fill in the form below and we’ll get back to you as soon as possible.

Oops. You seem to have written your full name in invisible ink. Please enter it so we can read it. Oops. You seem to have written your company in invisible ink. Please enter it so we can read it. It seems your e-mail doesn’t exist. Please enter a real one so we can contact you. Oops. You seem to have written your telephone in invisible ink. Please enter it so we can read it.