In this article I would like to explain how to integrate HTML5 + Javascript in a Windows Phone application and the same demonstrate how to call a .NET method from Javascript and how to call a Javascript method from .NET
So here's what we need to do to get started:
- Create a Windows Phone Silverlight application
- Add a WebBrowser component on the main page
- Set the IsScriptEnabled property of the WebBrowser component to true
- Add an event handler to the ScriptNotify event of the WebBrowser component
- Create a folder on the project called HTML and add the HTML, Javascript, and Stylesheet assets to this folder
- Write code to copy the HTML related assets to IsolatedStorage
- Set the source of the WebBrowser component to the main HTML page
Simple isn't it?
How it works
The steps above really do seem to be quite simple, and yes it really is. For Javascript to call into the host of the WebBrowser control we can use the window.external.notify() method. This is the same approach for having Javascript code execute code in the host application in other platforms. The window.external.notify() method takes a string which can be used to contain meta data that describes what you want the host to do. And for .NET code to execute Javascript code we use the InvokeScript() method of the WebBrowser control. The InvokeScript() method takes a string parameter that describes the Javascript method to execute, and a collection of strings that describe the arguments to be passed to the Javascript method to execute. If the method that will invoke a javascript function from the host is running on a non-UI thread (worker thread) then the best approach to using this method is by calling InvokeScript("eval", "methodName(args1,args2,args3)") instead of passing the name of the method to be invoked as the first method argument.
Here's a diagram I used in DDC 2012 that illustrates the process mentioned above:
For this example, we will have an application that hosts a HTML5 page that displays memory information of the device (as shown in the screenshot below)
And here's the code...
Default.html (HTML5 + Javascript)
The code below is going to be used as a local html file that is to be copied to isolated storage. Let's put this in a folder called HTML
MainPage.xaml
The code below is the main page of the Silverlight application that will host the HTML content
MainPage.xaml.cs
And here's the code behind the xaml file
What happens in the code above is that when the main page has loaded, the html assets are copied to isolated storage and loaded into the web browser component as a local file. When ScriptNotify is triggered, the Silverlight application retrieves memory information using the DeviceStatus class and passes this information back to the WebBrowser component by invoking the getMemoryUsageCallback() method using the InvokeScript() method of the WebBrowser component
The sample above is a very basic and naive but it demonstrates something that can provide endless platform interop possibilities. I hope you found this useful.
How it works
The steps above really do seem to be quite simple, and yes it really is. For Javascript to call into the host of the WebBrowser control we can use the window.external.notify() method. This is the same approach for having Javascript code execute code in the host application in other platforms. The window.external.notify() method takes a string which can be used to contain meta data that describes what you want the host to do. And for .NET code to execute Javascript code we use the InvokeScript() method of the WebBrowser control. The InvokeScript() method takes a string parameter that describes the Javascript method to execute, and a collection of strings that describe the arguments to be passed to the Javascript method to execute. If the method that will invoke a javascript function from the host is running on a non-UI thread (worker thread) then the best approach to using this method is by calling InvokeScript("eval", "methodName(args1,args2,args3)") instead of passing the name of the method to be invoked as the first method argument.
Here's a diagram I used in DDC 2012 that illustrates the process mentioned above:
For this example, we will have an application that hosts a HTML5 page that displays memory information of the device (as shown in the screenshot below)
And here's the code...
Default.html (HTML5 + Javascript)
The code below is going to be used as a local html file that is to be copied to isolated storage. Let's put this in a folder called HTML
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=480, height=800, user-scalable=no" />
<meta name="MobileOptimized" content="width" />
<meta name="HandheldFriendly" content="true" />
<title>HTML5 and Windows Phone 7</title>
<style>
body
{
color: White;
background-color: Black;
font-family: 'Segoe WP Semibold';
text-align: left;
}
h3
{
font-size: 20pt;
}
input
{
color: #ffffff;
background-color: #000000;
border: 2px solid white;
vertical-align: baseline;
font-size: 17pt;
min-width: 40px;
min-height: 40px;
margin: 5;
}
</style>
</head>
<body onload="onLoad()">
<div>
<h3>
Current memory usage:</h3>
<input id="memoryUsage" type="text" value="0" />
<h3>
Memory usage limit:</h3>
<input id="memoryUsageLimit" type="text" value="0" />
<h3>
Peak memory usage:</h3>
<input id="peakMemoryUsage" type="text" value="0" />
<h3>
Total memory:</h3>
<input id="totalMemory" type="text" value="0" />
</div>
<script type="text/javascript">
function onLoad() {
window.external.notify("getMemoryUsage");
}
function getMemoryUsageCallback(memoryUsage, memoryUsageLimit, peakMemoryUsage, totalMemory) {
document.getElementById("memoryUsage").value = memoryUsage;
document.getElementById("memoryUsageLimit").value = memoryUsageLimit;
document.getElementById("peakMemoryUsage").value = peakMemoryUsage;
document.getElementById("totalMemory").value = totalMemory;
}
</script>
</body>
</html>
MainPage.xaml
The code below is the main page of the Silverlight application that will host the HTML content
<phone:PhoneApplicationPage x:Class="PhoneApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignWidth="480"
d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait"
Orientation="Portrait"
shell:SystemTray.IsVisible="True"
Loaded="PhoneApplicationPage_Loaded">
<Grid x:Name="LayoutRoot"
Background="Transparent">
<phone:WebBrowser Name="browser"
IsScriptEnabled="True"
Source="HTML/Default.html"
ScriptNotify="browser_ScriptNotify" />
</Grid>
</phone:PhoneApplicationPage>
MainPage.xaml.cs
And here's the code behind the xaml file
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
}
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!store.DirectoryExists("HTML")) store.CreateDirectory("HTML");
CopyToIsolatedStorage("HTML\\Default.html", store);
}
}
private static void CopyToIsolatedStorage(string file, IsolatedStorageFile store, bool overwrite = true)
{
if (store.FileExists(file) && !overwrite)
return;
using (Stream resourceStream = Application.GetResourceStream(new Uri(file, UriKind.Relative)).Stream)
using (IsolatedStorageFileStream fileStream = store.OpenFile(file, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
{
int bytesRead;
var buffer = new byte[resourceStream.Length];
while ((bytesRead = resourceStream.Read(buffer, 0, buffer.Length)) > 0)
fileStream.Write(buffer, 0, bytesRead);
}
}
private void browser_ScriptNotify(object sender, NotifyEventArgs e)
{
var response = new object[]
{
DeviceStatus.ApplicationCurrentMemoryUsage,
DeviceStatus.ApplicationMemoryUsageLimit,
DeviceStatus.ApplicationPeakMemoryUsage,
DeviceStatus.DeviceTotalMemory
};
browser.InvokeScript("getMemoryUsageCallback", response.Select(c => c.ToString()).ToArray());
}
}
What happens in the code above is that when the main page has loaded, the html assets are copied to isolated storage and loaded into the web browser component as a local file. When ScriptNotify is triggered, the Silverlight application retrieves memory information using the DeviceStatus class and passes this information back to the WebBrowser component by invoking the getMemoryUsageCallback() method using the InvokeScript() method of the WebBrowser component
The sample above is a very basic and naive but it demonstrates something that can provide endless platform interop possibilities. I hope you found this useful.
You can grab the full source code the sample above here:
I have no words for this great post such a awe-some information i got gathered. Thanks to Author.
ReplyDeletehtml5 converter
for more PHP tutorials click here
ReplyDeletewww.daddysoft.com
This is a great site. Content was great. Keep it up.html5
ReplyDeleteGood post. one more post like this http://aspnettutorialonline.blogspot.com/2012/09/javascript-design-patterns-book-free.html
ReplyDeleteHTML 5 is the latest version of HTML. By using this developer can easily add any video or audio files with some other advantages like; Elegant form, offline application cache etc.
ReplyDeletehtml5
Hi, what if the html5 content has multiple files and folders? should we take them to the isolated storage too? if yes can you guide please
ReplyDeleteRegards