WebView - Dynamic Html Page with Images (MVVM)

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


 



Leave a Comment
  • Please add 3 and 5 and type the answer here:
  • Post
Wiki - Revision Comment List(Revision Comment)
Sort by: Published Date | Most Recent | Most Useful
Comments
  • Naomi  N edited Revision 18. Comment: Very nice article!

  • Naomi  N edited Revision 16. Comment: Minor edit

  • Sachin  S edited Revision 15. Comment: Fixed typo

  • Sachin  S edited Revision 14. Comment: Corrected typo

  • Sachin  S edited Revision 13. Comment: Finishing initial draft

  • Sachin  S edited Revision 12. Comment: Updated Code

  • Sachin  S edited Revision 11. Comment: Finishing initial draft

  • Sachin  S edited Revision 10. Comment: Finishing initial draft

  • Sachin  S edited Revision 9. Comment: Finishing initial draft

  • Sachin  S edited Revision 8. Comment: Finishing initial draft

Page 1 of 2 (18 items) 12
Wikis - Comment List
Sort by: Published Date | Most Recent | Most Useful
Posting comments is temporarily disabled until 10:00am PST on Saturday, December 14th. Thank you for your patience.
Comments
  • Naomi  N edited Original. Comment: Minor correction

  • Sachin  S edited Revision 1. Comment: Finishing initial draft

  • Sachin  S edited Revision 2. Comment: Finishing initial draft