advanced web statistics

External URLs and Phone Numbers in WP7 WebBrowser Control

The Windows Phone 7 WebBrowser is garbage.  F**king horrible. If you want to display basic HTML it's great.  If you want to display HTML that users can interact with (i.e. clicking hyperlinks, mailto: links, or dial phone numbers) it's basically useless.  Don't even get me started on opacity and background images.  In developing a Windows Phone 7 application recently there was a need to link to a mobile-enabled website. In said website there were pages with phone numbers, email addresses, etc... A business requirement for the application was to open up the mail client, dial a phone number, or open a hyperlink when a user clicked on these links.  No duh right?  I thought the WebBrowser would at least be able to parse out links with href and mailto and since it's built for a PHONE it should be smart enough to detect tel.  Fail.

At this point we had a couple of options (Mango is NOT an option at this point):
  1. Recreate the external site in XAML with event handlers for the "hyperlinks" which would end up being styled textblock controls
  2. Take a screenshot of the mobile site and place rectangles over the hyperlinks and wire those up to events
  3. Download the HTML from the site asynchronously, parse HTML and find head or title tags, inject JavaScript to find and enumerate all a tags and wire up an onclick event to raise the ScriptNotify event [via window.external.Notify], call the WebBrowser's NavigateToString method and pass in this newly-constructed HTML, figure out what kind of link was clicked and then fire an appropriate task
Before I talk about which option I chose, take a minute to soak in the absurdity of the aforementioned solutions (FYI - I chose 3). Take this simple example site here:

simple webbrowser example 1

And here's the markup (unadulterated)

simple webbrowser example 2

Simple enough right? You can clearly see that the links are sporting the correct syntax. Time to start hacking.

The first thing we need to do is add JavaScript to get all of our a tags. Once we have this we simply need to enumerate and attach an onclick event. I'm not a JavaScript expert by any means but think this fairly unobtrusive. This JavaScript is going to remain constant so we should use the const string:

simple webbrowser example 3

The next thing we need to do is wire up the WebBrowser control. The most important part is to enable scripting via the IsScriptEnabled property. This is set to false by default and resulted in many f-bombs being dropped until I figured this out. We will also need to wire up the ScriptNotify event. This is how the WebBrowser will communicate with our application.

simple webbrowser example 4

In the LoadedComplete method we perform an asynchronous request via WebClient object to get the source HTML from the server. We then create a StringBuilder instance and insert our JavaScript just before the </title> tag.

Now that the ScriptNotify event is wired up we can set a breakpoint in our code, run the application, and determine which link was clicked when we tap the link.

simple webbrowser example 5

In the case above, we'll want to launch the EmailComposeTask.

simple webbrowser example 6

Running this code in the emulator and we get the following:

simple webbrowser example 7

I don't have a mail account setup in the emulator (is this possible?) so we see the fail message. But if I did in fact have an email account setup it would display appropriately. For other scenarios you would use the appropriate phone task.

Easy enough. This code isn't production-ready by any means. I just wanted to quickly share with others how to accomplish a task that should be a native experience (IMO). I will clean this up and add logic for things such as detecting if there is actually a title tag, confirming that a task is about to be shown, cleaning up the ScriptNotify event handler, etc... This would take about 3 seconds using Interface Builder in Mac OS (iOS development). iOS developers have the luxury of checking boxes for detecting various links in text controls.

Original inspiration: Integrated Links and Styling for Windows Phone 7 WebBrowser Control

Tags: C#, Silverlight, Windows Phone

Json.NET and Generic HttpWebRequest Responses FTW

Working on a Windows Phone 7 mobile app recently, I found myself writing a bunch of similar / redundant code for HttpWebRequest response handling. By "a bunch" I mean in the neighborhood of 3 methods.... Hello Generics!!!

If I find myself writing the same handler more than once and the only difference is the type of object I am returning I ALWAYS (at least try to) write a generic method to take care of the heavy lifting.  There are a plethora of reasons to use Generics when the opportunity presents itself and I'm not going to start listing them.  Those of you that understand .NET Generics will get it.  If you are a .NET developer and currently developing applications targeting version 2.0 or greater and aren't familiar with Generics, then I highly suggest you educate yourself: Generics in the .NET Framework.

If you are still with me and are familiar with the System.Net namespace and the HttpWebRequest class (as it pertains to Silverlight and/or Windows Phone 7), I'd like to share the following response handler for dealing with Asynchronous requests:

private static T ProcessFamiliarRequestResponse<T>(IAsyncResult asyncResult)
{
    HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
    HttpWebResponse httpWebResponse = (HttpWebResponse)request.EndGetResponse(asyncResult);

    using (StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream()))
    {
        return JsonWorker.TooEasyToDeserializeJsonObject<T>(streamReader.ReadToEnd());
    }
}

If this doesn't make sense to you I highly suggest reading up on WebClient and HttpWebRequest usage.  If you are familiar, I hope you can appreciate that this is one point of entry into handling an infinite number of requests (within reason).

It gets cleaner: Enter Json.NET.  Personally, I like to create clean POCO's to return data to the consumer.  I have seen way too many examples creating objects that conform EXACTLY to the Json format returned from any given request.  For instance:

public class Employee
{
    public string employee_first_name { get; set; }
    public string employee_last_name { get; set; }
    public string employee_job_description { get; set; }
}

Gross (imo).  .NET is so much better than this.  I take pride in the code that I deliver and personally believe the following class is much cleaner (and not to mention, conforms to .NET naming conventions):

public class Employee
{
    [JsonProperty("employee_first_name")]
    public string FirstName { get; set; }

    [JsonProperty("employee_last_name")]
    public string LastName { get; set; }

    [JsonProperty("employee_job_description")]
    public string JobDescription { get; set; }
}

This way you can map your neatly-defined POCO properties to their disgusting origins.  The following generic method for deserializing your Json results works fairly well (pre-supposing you decorated your POCO(s) with the JsonProperty attribute OR left it repulsive and/or primitive):

public static class JsonWorker
{
    public static T DeserializeJsonObject<T>(string result)
    {
        return JsonConvert.DeserializeObject<T>(result);
    }
}

If you want to take it a step further, you could add the following method to your JsonWorker class to serialize your objects. Think storing application state in IsolatedStorage or updating your light-weight, client-side database (via Sterling (which is AWESOME!!!)):

public static string WayEasierToSerializeObjectToJson(object randomPOCO)
{
    return JsonConvert.SerializeObject(randomPOCO);
}

Easy.

Tags: C#, Code, Windows Phone

Debug a Windows Phone 7 Application After a Tombstone

In debugging a Windows Phone 7 issue related to application state and tombstoning recently, I found that the Visual Studio debugger stops after the application comes back from a tombstone (press the Windows putton on Windows Phone 7 emulator, then press device back button to reactivate the application).  A quick Google search and I ran across a little gem on Shawn Wildermuth's blog.

Solution:  Press F5 again while the emulator is displaying the "Resuming...." progress indicator. 

Easy.

Tags: Windows Phone

Set Silverlight Startup Page

In sandboxing Windows Phone 7 recently I came across the need to change my startup page.  The reasoning for this is simple: I have a core of the work completed and I want to sandbox a data call before I implement in the actual application.  With conventional web projects this is as easy as right-clicking the file you want to and click 'Set As Start Page'. With the Windows Phone 7 SDK this luxury does not exist.

There is however a way to accomplish this with a little bit of code.  Simply open up your projects App.xaml.cs and implement an Application_Startup method.

private void Application_Startup(object sender, StartupEventArgs e)
{
    RootVisual = new SandboxPage();
}

SandboxPage is the name of my XAML page in this example. Here we simply set the RootVisual to an instance of our new page.

The second piece to this is registering this startup method in the App constructor a la:

public App()
{
    Startup += Application_Startup;
}

This doesn't necessarily apply to Windows Phone 7.  General Silverlight.

Easy.

Tags: C#, Silverlight, Windows Phone

Hello Windows Phone

Today the Community Technology Preview release of Visual Studio 2010 Express for Windows Phone 7 was released. For those not in the know, this release provides 100% compatibility with the final version of Visual Studio 2010.

You can get it here: Visual Studio 2010 Express for Windows Phone 7

I have been interested in and writing XNA for a couple of months now and will start posting more regularly thanks to this new addition.

Stay tuned!

Tags: Windows Phone, XNA