WebView - Dynamic Html Page with Images (MVVM)

This article provides support for WebView in Windows 8 to display local html file or html page created dynamically. Oftentimes developers are looking to display local html file but due to the WebView restrictions (for security reasons) are not able to achieve it.  This also caters to following Code Sample Requests -> (1, 2)

Also, this article shows basic implementation of MVVM design pattern. The only page (MainPage - see code here)  in project has bare minimum code-behind in MainPage.xaml.cs, just constructor (MainPage()) and empty functions (LoadState and SaveState), which is inline with basic guiding principle of MVVM to keep Model, ViewModel and View totally decoupled (or loosely coupled). 

http://gallery.technet.microsoft.com/WebView-Dynamic-Html-Page-f0e0ada4

Introduction

The sample mentioned in this article shows how to create a dynamic html page, preview that in WebView and finally save that html page into machine. During page save operation, user can save images separately to local drive or just keep them in html page in Base64 encoded form.  The sample uses Javascript Eval, Image **Base64 **encoding and Webview **InvokeScript **to support html page preview with local images inside WebView. 

Note : Before we go any further it is important to note that with Windows 8.1, WebView by default supports the loading of local html file.  Windows 8.1 still has some time to hit the market.

Having said that, this sample covers the implementation of other concepts which are mentioned under Noteworthy section. 

↑ Return to Top


 

Description

We will briefly go through the important portion of sample here. 

To start with, we will include an HtmlPageHolder.htm in project Assets folder as dummy place holder where we are going to inject dynamic or local html source into.

<html> 
<head> 
     <script type='text/javascript'></script> 
</head> 
<body> 
    <div id="ContentPlaceHolder"></div> 
</body> 
</html>

 

Inside our webview we will refer this html as shown below.

<WebView Name="webView"  Source="ms-appx-web:///Assets/HtmlPageHolder.htm"/>

 
Once user has entered the text and selected images, Preview button in sample takes care of generating html source code and showing the preview. 

Note here we are passing whole **WebView object **using element name as command parameter. 

<Button Grid.Row="1" Grid.Column="1" Command="{Binding GenerateHtmlPageCommand}" CommandParameter="{Binding ElementName=webView}"
                   HorizontalAlignment="Center" VerticalAlignment="Top" Height="100" Style="{StaticResource PreviewHtmlButtonStyle}" IsEnabled="{Binding Path=IsGenerateHtmlPageButtonEnabled, Mode=TwoWay}"></Button>

In case html file is already present in local folder, we can skip to preview part, just read that source and parse it and replace the image with Image64 (discussed in this MSDN forum) and inject the referred scripts directly inside html.

After we have read/generated the well html source and processed it,  we are ready to display it in WebView. Here is re-cap of important points -

  1. Replace/Inject Images link with Base64 representation.
  2. Inject script file with actual css source. 

In this sample we will read all images and replace them with their Base64 string representation using following function

public async static Task<string> getBase64ImageString(IStorageFile image) 
        { 
            string base64ImageString = string.Empty; 
            try
            { 
                IRandomAccessStream readStream = await image.OpenAsync(FileAccessMode.Read); 
                IInputStream inputStream = readStream.GetInputStreamAt(0); 
                DataReader dataReader = new  DataReader(inputStream); 
  
                uint numOfBytes = await dataReader.LoadAsync((uint)readStream.Size); 
                byte[] bytes = new  byte[numOfBytes]; 
                dataReader.ReadBytes(bytes); 
                base64ImageString = Convert.ToBase64String(bytes); 
            } 
            catch (Exception ex) 
            { 
                WebViewUtils.LogException(ex); 
            } 
            return base64ImageString; 
        }

Once we have image base64 representation ready, we generate html content to inject into our dummy html page

public static  string GenerateHtmlContent(string headerText, IList<WebViewImage> webViewImages)  
        { 
            string htmlPage = null; 
            try
            { 
                if (webViewImages != null) 
                { 
                    StringBuilder sb = new  StringBuilder(); 
                    if (headerText.Length > 0) 
                        sb.Append(string.Format(WebViewConstants.HTML_PARAGRAPH_TAG_NO_NEWLINE, headerText)); 
                    foreach (WebViewImage webViewImage in webViewImages) 
                    { 
                        sb.Append(string.Format(WebViewConstants.HTML_IMAGE_BASE64_TAG_NO_NEWLINE, webViewImage.Base64String)); 
                    } 
                    htmlPage = sb.ToString(); 
                } 
            } 
            catch (Exception ex) 
            { 
                WebViewUtils.LogException(ex); 
            } 
            return htmlPage; 
        }

 And finally, we inject the above generated html content as shown below

public static  bool InjectHtmlIntoPage(WebView webView,  string  htmlPageContent, string divElementId) 
        { 
            bool success = false; 
            try
            { 
                StringBuilder sb = new  StringBuilder(); 
                sb.Append("function addHtmlContentToDiv()"); 
                sb.Append("{"); 
                sb.Append(string.Format("    var placeHolderElement = document.getElementById('{0}');", divElementId)); 
                sb.Append("    if (placeHolderElement) {"); 
                sb.Append("        placeHolderElement.innerHTML ='"); 
                sb.Append(htmlPageContent); 
                sb.Append("';"); 
                sb.Append("    }"); 
                sb.Append("}"); 
                string script = sb.ToString(); 
                webView.InvokeScript("eval", new  string[] { script }); 
                webView.InvokeScript("eval", new  string[] { "addHtmlContentToDiv()" }); 
                success = true; 
            } 
            catch (Exception ex) 
            { 
                WebViewUtils.LogException(ex); 
            } 
            return success; 
        }

 
For full details and exact workflow please go through the project link at the end. 
 

With Windows 8.1 coming out soon, we may not need all things here but they are still relevant in case user want to inject their own html code or css or change background once page is loaded and displayed in WebView.

↑ Return to Top


 

MSDN Q&A Threads

MSDN questions answered by me and covered in this article.

Q-I. Display Image in webview form local html in C#
Q-II. How to apply CSS or formatting to RSS dynamic HTML ?
Q-III. How to Read HTML file and images from Local Folder?
Q-IV. Adding div tags to body of html page during run time
Q-V. Asking for MVVM in C# - Xaml to build Windows store app
Q-VI. Accessing Image & HTML files in KnownsFolder

↑ Return to Top


 

Noteworthy

  

Noteworthy things implemented in sample or covered in this article

  1. Injecting CSS into html page. (Refer Q-II)
  2. Injecting div tags into html page. (Refer Q-IV)
  3. Parsing and reading html file to use in NavigateToString.  (Refer Q-I)
  4. Basic MVVM implementation, includes Data and Command Binding.(Refer Q-V)

↑ Return to Top


 

Browse Code

Just want to browse the code, click here

The Project

This document describes the project available for download at TechNet Gallery

http://gallery.technet.microsoft.com/WebView-Dynamic-Html-Page-f0e0ada4

↑ Return to Top