PhoneGap on WP7 Tip #2: Script interaction

(This post is part of my series PhoneGap on Windows Phone 7 tips.)

When you are creating integration points between your PhoneGap HTML5 application and the Silverlight hosting application, there are a few ways you can go about crossing the gap (pun intended). This tip is an example of one of those techniques. It’s very flexible, and is typically going to be used when you have one off types of code being written on both sides. We’re able to do this because the PhoneGap user control actually wraps a Windows Phone WebBrowser control, and we can access that internal WebBrowser and use the InvokeScript method and the ScriptNotify event to do what we want here. If you’re curious as to all the details about the WebBrowser control and if there’s other things you can do in the context of a PhoneGap application, you can read about it on the MSDN site.

As a side note, if you try the examples below and your version of PGView does not seem to have a Browser member, you’re probably working with an older version of the PhoneGap user control. To get the latest version, you’ll need to download the framework for the control, build that project, then add output of that to your project. To do that, open the solution WP7GapClassLib in the framework folder of the WP7GapBuild project. Build that solution. Then, when you create a project from the GapAppStarter template, simply right-click on the GapLib folder, choose Add Existing Item, then browse to the location where the WP7GapClassLib project is stored. Then drill down to the bin\debug folder and pick the WP7GapClassLib.dll file in there. Your references to it should update automatically.

This script integration technique is bidirectional. You can have the hosting page’s code call into the script in the PhoneGap application, and you can have JavaScript code in the PhoneGap application call code in the hosting Silverlight page.

Let’s start with a simple button on the Silverlight host page to trigger the code we want to run. On MainPage.xaml, go into designer view, then make room at the bottom of the page for the controls we’re going to add by resizing the PhoneGap control up just a little. Use the grab handle at the bottom of the control, it’s a downward facing triangle. Open the Toolbox at the left side of Visual Studio, if it’s not already open. In there you’ll see a lot of the basic Silverlight controls you can add to a page. Look for the Button control, drag it onto the page below the PhoneGap control. Then set its Content property to “To PhoneGap”. You can use the Property window to the right, or just change it inline in the XAML code.

To create an event handler, double click the button. That will open a code window and position your cursor inside the newly created button1_Click event handler. Here is where we call the script in PhoneGap. Type in PGView.Browser.InvokeScript(“button1_Click”); Your code window should look like this:

 private void button1_Click(object sender, RoutedEventArgs e)
 {
     PGView.Browser.InvokeScript("button1_Click",textBox1.Text.ToString());
 }

Now we need to create a JavaScript function called button1_Click and put our code in it. In the <script> section at the top of index.html in the WWW directory of the project, put in the following script:

 function button1_Click() {
           document.getElementById("welcomeMsg").innerHTML = "You clicked!";
       }

You could call the function anything you want, but for consistency in the demo I set it up this way. Run the project, click the button, and you should see the HTML change to “You clicked”.

You can also pass parameters into the script. Go back to the Silverlight page and add a TextBox to the right of the button. Your screen should look a little like this:

image

Set the Text property of the text box to be an empty value. Change the code in the button click event handler to include sending the Text of the textbox to the script handler.

 private void button1_Click(object sender, RoutedEventArgs e)
{
    PGView.Browser.InvokeScript("button1_Click",textBox1.Text.ToString());
}

Then, we need to update the JavaScript button1_Click function to accept the parameter:

 function button1_Click(textbox) {
    document.getElementById("welcomeMsg").innerHTML = "The TextBox says: " + textbox;
}

That parameter could be a collection/array too, if you need it.

(By the way, as you run this sample and click in the text box to type, you’ll see the emulator’s onscreen keyboard appear. The first thing to notice is that it slides your PhoneGap display up and off the screen. We’ll address that in a later article. Secondly, if you’d like to type with your computer’s keyboard rather than clicking the letters on the screen, just press Pause or Page Up / Page Down to toggle that.)

Going the other direction is a bit trickier, since you need to tell the host Silverlight page to expect a call “up” from the WebBrowser control inside the PhoneGap control. Add a button to the HTML page like so:

 <button onclick="window.external.Notify('clearTextBox');">clear textbox</button>

Unlike calling into the PhoneGap’s browser script engine, calling out of it to the host page always raises a single event – Browser_ScriptNotify. We create an event handler for this in the host page’s constructor method. The constructor is the method with the same name as the host page. In our example it’s public MainPage() . Find that method at the top of the MainPage.xaml.cs file. At the end of that method, type PGView.Browser.ScriptNotify Then type a space, a plus, and an equals. Follow that with two presses on the Tab key. Congratulations, you just learned how to create and wire up an event handler in XAML! That will be a handy set of keystrokes in the future.

In the newly generated Browser_ScriptNotify method, delete the line that throws a NotImplemented exception, since we’re implementing the function. Look at the method parameters. The second one e is of type NotifyEventArgs. All you really need to know here is that e.Value will contain the string sent from the window.external.Notify call from the PhoneGap control. So let’s write code to handle it.

 void Browser_ScriptNotify(object sender, NotifyEventArgs e)
{
    string commandStr = e.Value;

    if (commandStr == "clearTextBox")
    {
        textBox1.Text = "";

    }
}

Run the project, type some text in the text box, then press the clear textbox button. The text in the textbox should be cleared.

As you add more places where your JavaScript inside your PhoneGap app needs to talk to the hosting page, you’ll just add new if statements in this event handler. You could get creative and pass an array serialized into json, with perhaps the name of an “action” prepended in front of it in the string.

Let me know your questions or comments about this technique below!