Full Web Browser Control for Windows Phone 7

Web vs Native vs Hybrid Applications

Windows Phone development has a lot of flavors. There are three different ways to create Windows Phone applications: web based, native and hybrid applications. The first, web based applications, are done and hosted completely on the web and accessed using the phone browser. This type of application is the most portable because it can be accessed through most of the web browsers. The problem with creating web based mobile applications is that you lose most of the functionality that the platform can give you. The second way of creating a Windows Phone application is developing a native application. This type of application is the most commonly used  when you want to  takes advantage of the features that the platform has to offer. The problem with native applications is that cross platform maintenance tends to be a challenge because of the time and knowledge it consumes. And last but not least the best of the both worlds, what I like to call the Hybrid Mobile Application. This type of application enjoys the portability of a web based application and lets us work with the features that the platform can offer us. A an example of the advantages of a hybrid application would be a search application that uses the GPS on the mobile to get more accurate results and a web browser to show the results.

The Problem

Developing hybrid applications for the Windows Phone platform requires that we include a web browser control and extend the application with any feature with the phone functionality. But the problem that I have encountered while developing this type of applications is that the Web Browser Control included with the Windows Phone Developer Tools does not include any history or navigation as in forward, back and refresh. The lack of this functionality makes the web browser control hard to develop with. In this post we are going to be creating a browser control that enables forward, back and refresh navigation and also saves the history. Also we are going to include a progress bar to let the user know that we are navigating and that the application did not freeze.

Creating the Control

First we are going to create a Windows Phone Class Library Project on Visual Studio 2010.

  1. Open Visual Studio 2010 go to File->New->Project…
  2. Select Windows Phone Class Library from the project templates.
  3. Add FullBrowserControl to the project name
  4. Press Ok to create the project.
New Windows Phone Class Library Project

New Windows Phone Class Library Project

After creating the project delete the Class1.cs auto generated file and add a new Windows Phone User Control.

  1. Right click on the FullBrowserControl solution, Add->New Item
  2. In the dialog add a Windows Phone User Control and name it FullBrowserControl.xaml
  3. Click Ok.
New Windows Phone User Control Item

New Windows Phone User Control Item

Creating the Interface of Our Control

Once we have added the new User Control we are going to create our Full Browser Control’s user interface. For this we first need to download and install the Silverlight Toolkit for Windows Phone which includes a lot of new controls for Windows Phone and in particular the PerformanceProgressBar that we are going to be using to alert the user that the browser is navigating.  Now let’s add some row definitions to the User Control content grid:

<Grid Name="ContentGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
</Grid>

Now we will add the PerformanceProgressBar and we are going to bind the IsIndeterminate property to a ShowProgress DependencyProperty that we are going to be creating in a moment.

<Grid Name="ContentGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>

        <toolkit:PerformanceProgressBar             x:Name="performanceProgressBar"             IsIndeterminate="{Binding ShowProgress}"             Background="{StaticResource PhoneBackgroundBrush}"         />
 </Grid>

And last but not least we are going to add a regular WebBrowser control. it is very important that the IsScriptEnabled property is set to true because we are going to be invoking JavaScript from the browser in order to navigate between pages. Also we are going to need the Navigated, Navigating and Loaded event handlers.

<Grid Name="ContentGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>

        <toolkit:PerformanceProgressBar             x:Name="performanceProgressBar"             IsIndeterminate="{Binding ShowProgress}"             Background="{StaticResource PhoneBackgroundBrush}"         />

        <phone:WebBrowser             Name="TheWebBrowser"             Grid.Row="1"             Background="{StaticResource PhoneBackgroundBrush}"             IsScriptEnabled="True"             Navigated="TheWebBrowser_Navigated"             Navigating="TheWebBrowser_Navigating"             Loaded="TheWebBrowser_Loaded"         />
 </Grid>

Now we need to open the FullWebBrowser.xaml.cs file to start working our logic.

Creating our Logic

In order to set up all the bindings correctly we need to set the DataContext of the grid to the FullWebBrowser object like this:

public partial class FullWebBrowser : UserControl
{
    //ctr
    public FullWebBrowser()
    {
        InitializeComponent();

        //Set the data context for the bindings.
        ContentGrid.DataContext = this;
    }
}

Now that we have set up the DataContext of our FullBrowserControl we are going to add some fields that we are going to be using for our logic. First we are going to add a Stack named  _NavigatingUrls that is going to be used to store the previous urls that we can navigate to. Then we need to add an ObservableCollection named _History that is where we are going to store the navigation history for our browser, we also need to create a readonly property named History that will let us access the _History field. And last but not least we need a flag to validate if the user is navigating back or not, for this we are going to use a bool variable named _IsNavigatingBackward with the false as the default value.

#region Fields

    //The navigation urls of the browser.
    private readonly Stack<Uri> _NavigatingUrls = new Stack<Uri>();

    //The history for the browser
    private readonly ObservableCollection<string> _History =
       new ObservableCollection<string>();

    //Flag to check if the browser is navigating back.
    bool _IsNavigatingBackward = false;

    #endregion Fields

    #region Properties

    ///
<summary>
    /// Gets the History property for the browser.
    /// </summary>

    public ObservableCollection<string> History
    {
        get { return _History; }
    }

#endregion Properties

Now we are going to create three dependency properties. One is a ShowProgress boolean value that is the flag we are going to use to display our progress bar while we navigate in our browser also as you remember is the value that we binded to the IsIndefinite property of the PerformanceProgressBar. The second, a CanNavigateBack boolean value to determine if the browser is able to navigate back and the third a InitialUri string that is going to be the initial uri that our browser should navigate when the browser loads for the first time.

#region Dependency Properties

    ///
<summary>
    /// ShowProgress Dependency Property
    /// </summary>

    public static readonly DependencyProperty ShowProgressProperty =
        DependencyProperty.Register("ShowProgress", typeof(bool),
        typeof(FullWebBrowser), new PropertyMetadata((bool)false));

    ///
<summary>
    /// Gets or sets the ShowProgress property. This dependency property
    /// indicates whether to show the progress bar.
    /// </summary>

    public bool ShowProgress
    {
        get { return (bool)GetValue(ShowProgressProperty); }
        set { SetValue(ShowProgressProperty, value); }
    }

    ///
<summary>
    /// CanNavigateBack Dependency Property
    /// </summary>

    public static readonly DependencyProperty CanNavigateBackProperty =
        DependencyProperty.Register("CanNavigateBack", typeof(bool),
        typeof(FullWebBrowser), new PropertyMetadata((bool)false));

    ///
<summary>
    /// Gets or sets the CanNavigateBack property. This dependency property
    /// indicates whether the browser can go back.
    /// </summary>

    public bool CanNavigateBack
    {
        get { return (bool)GetValue(CanNavigateBackProperty); }
        set { SetValue(CanNavigateBackProperty, value); }
    }

    ///
<summary>
    /// InitialUri Dependency Property
    /// </summary>

    public static readonly DependencyProperty InitialUriProperty =
        DependencyProperty.Register("InitialUri", typeof(string),
        typeof(FullWebBrowser), new PropertyMetadata((string)String.Empty));

    ///
<summary>
    /// Gets or sets the InitialUri property. This dependency property
    /// indicates the initial uri for the browser.
    /// </summary>

    public string InitialUri
    {
        get { return (string)GetValue(InitialUriProperty); }
        set { SetValue(InitialUriProperty, value); }
    }

#endregion Dependency Properties

Now that we have all our Fields, Properties and Dependency Properties set up we need to create the event handlers that we added to the WebBrowser control.

#region Event Handlers

    void TheWebBrowser_Navigating(object sender,
        Microsoft.Phone.Controls.NavigatingEventArgs e)
    {
    }

    void TheWebBrowser_Navigated(object sender,
        System.Windows.Navigation.NavigationEventArgs e)
    {
    }

    private void TheWebBrowser_Loaded(object sender, RoutedEventArgs e)
    {
    }

 #endregion Event Handlers

First let’s start with the Loaded event. We are going to use the InitialUri and navigate to it.

#region Event Handlers

    void TheWebBrowser_Navigating(object sender,
        Microsoft.Phone.Controls.NavigatingEventArgs e)
    {
    }

    void TheWebBrowser_Navigated(object sender,
        System.Windows.Navigation.NavigationEventArgs e)
    {
    }

    private void TheWebBrowser_Loaded(object sender, RoutedEventArgs e)
    {
        //When we load our browser if we specified an initial uri
        //we navigate to it.
        if(!String.IsNullOrEmpty(InitialUri))
            TheWebBrowser.Navigate(new Uri(InitialUri));
    }

 #endregion Event Handlers

By using the Navigate method of the browser we activate the Navigating event. Every time that we start navigating we want to show the PerformanceProgressBar to alert the user that the browser is navigating. To do this we set the ShowProgress dependency property to true.

#region Event Handlers

    void TheWebBrowser_Navigating(object sender,
        Microsoft.Phone.Controls.NavigatingEventArgs e)
    {
        //We show the progress bar when we start navigating.
        ShowProgress = true;
    }

    void TheWebBrowser_Navigated(object sender,
        System.Windows.Navigation.NavigationEventArgs e)
    {
    }

    private void TheWebBrowser_Loaded(object sender, RoutedEventArgs e)
    {
        //When we load our browser if we specified an initial uri
        //we navigate to it.
        if(!String.IsNullOrEmpty(InitialUri))
            TheWebBrowser.Navigate(new Uri(InitialUri));
    }

 #endregion Event Handlers

The last event is the browser Navigated handler. Here is where we are going to be giving our control the logic to determine if he can navigate backward or forward and save a history of our navigation every time we go to a different url or navigate within a website. The first thing we are going to do is verify if we are navigating back or forward and if we can navigate back. If we are navigating forward meaning that the _IsNavigatingBackward flag is set to false we are going to add the new url, the one that we are navigating to, to our url stack, also we will add it to our history but only if the url is not already in our history. But if the _IsNavigatingBackward flag is set to true and we can navigate back we just need to remove the top url from our _NavigatingUrls stack. Then we check if there is only one url in our stack remaining. If there is more than 1 url in our stack that means that we can navigate back and we set the CanNavigateBack flag to true, if there is only one left the we cannot navigate back so we set the CannavigateBack flag to false. And last but not least we can hide our PerformanceProgressBar setting our ShowProgress dependency property to false.

#region Event Handlers

    void TheWebBrowser_Navigating(object sender,
        Microsoft.Phone.Controls.NavigatingEventArgs e)
    {
        //We show the progress bar when we start navigating.
        ShowProgress = true;
    }

    void TheWebBrowser_Navigated(object sender,
        System.Windows.Navigation.NavigationEventArgs e)
    {
        //If we are Navigating Backward and we Can Navigate back,
        //remove the last uri from the stack.
        if (_IsNavigatingBackward == true &amp;amp;&amp;amp; CanNavigateBack)
            _NavigatingUrls.Pop();

        //Else we are navigating forward so we need to add the uri
        //to the stack.
        else
        {
            _NavigatingUrls.Push(e.Uri);

            //If we do not have the navigated uri in our history
            //we add it.
            if (!_History.Contains(e.Uri.ToString()))
                _History.Add(e.Uri.ToString());
        }

        //If there is one address left you can't go back.
        if (_NavigatingUrls.Count > 1)
            CanNavigateBack = true;
        else
            CanNavigateBack = false;

        //Finally we hide the progress bar.
        ShowProgress = false;
    }

    private void TheWebBrowser_Loaded(object sender, RoutedEventArgs e)
    {
        //When we load our browser if we specified an initial uri
        //we navigate to it.
        if(!String.IsNullOrEmpty(InitialUri))
            TheWebBrowser.Navigate(new Uri(InitialUri));
    }

 #endregion Event Handlers

Finally we need to add our private methods to navigate back, forward and refresh our FullBrowserControl. Let’s start with the navigate forward method. To navigate forward we simply need to set the _IsNavigatingBackward to false and invoke the JavaScript code to navigate forward (“history,go(1)”).

 ///
<summary>
 /// Used to navigate forward.
 /// </summary>

 public void NavigateForward()
 {
     _IsNavigatingBackward = false;
     TheWebBrowser.InvokeScript("eval", "history.go(1)");
 }

Navigating back and refresh work in the same way as NavigateForward. When navigating back we set the _IsNavigatingBack to true and invoke the JavaScript code to navigate back (“history.go(-1)”).  To refresh our browser we only need to invoke the JavaScript code for refresh (“history.go()”)  and we do not need to set any flag because refreshing the browser does not activate neither the Navigating nor Navigated handlers of the browser so we do not change anything on our history or navigating uris.

 ///
<summary>
 /// Used to navigate back.
 /// </summary>

 public void NavigateBack()
 {
     _IsNavigatingBackward = true;
     TheWebBrowser.InvokeScript("eval", "history.go(-1)");
 }

 ///
<summary>
 /// Used to refresh the browser.
 /// </summary>

 public void RefreshBrowser()
 {
     TheWebBrowser.InvokeScript("eval", "history.go()");
 }

And the last method we are going to expose is a Navigate method that calls the internal Browser to navigate to a specified url.

 ///
<summary>
 /// Used to navigate to a specified url.
 /// </summary>

 /// <param name="Url">The web address.</param>
 public void Navigate(string Url)
 {
     TheWebBrowser.Navigate(new Uri(Url, UriKind.Absolute));
 }

That is it. Our FullBrowserControl is ready. We have a browser that navigates to urls, navigates back, navigates forward, refresh and saves the history for us and let us handle the back button marketplace requirement with the CanNavigateBackward property when developing hybrid applications. To see how it works I am including the source code here (FullBrowserSample.zip).

P.S. There are some methods remaining like the InvokeScript and the InvokeScriptCompleted handler that can be exposed as needed.

Thanks’ everyone for reading. Come back later for more posts on Francisco’s Development Corner. ENJOY!!!!

34 thoughts on “Full Web Browser Control for Windows Phone 7

  1. Pingback: Full Web Browser Control for Windows Phone 7 | www.nalli.net

  2. Hi Francisco, excellent control. Thank you very much for sharing it with us. Is copy and paste functionality available through this custom control? I haven’t seen it available in the standard Web Brower Control.

    • Hello Ram,

      The browser already has the copy paste enabled. You might have not seen it because copy/paste will only be enabled for input text as in text boxes in app controls and Web. Text blocks or static/output text cannot be copied or pasted. So for now this is a copy/paste limitation. If you have the latest WP7 Emulator and Tools you should be able to try copy/paste, to do this simply open the sample app that I included in this post and do the following:

      1. Navigate to any page where you can input text such as http://www.bing.com.
      2. Write something in the search box.
      3. Un-focus the search box by clicking anywhere on the page.
      4. Re-select what you just wrote and the copy option should appear.

      I hope this can help and thanks for reading.

      Cheers,
      Francisco J. Fernandez

      • Hello fjfernandez,
        Can you tell me how to insert a search box for this full webBrowser control. Or Can you tell me the source code for this Navigation. Please mail me the source code – rghv.rocking@gmail.com.

  3. Pingback: Full Web Browser Control for Windows Phone 7 | www.nalli.net

  4. Great post Francisco. I have a related question and I was hoping you could share your thoughts on it. I am getting back into SW development so although a lot of these new technologies are extremely new to me, I have been able to use the basic knowledge I had learned before to make sense of what I am trying to do.

    Some background: I am basically wanting to communicate with a restful web service called Proxomo (Proxomo.com) and I am working specifically on calling it to perform the login functionality. Behind the scenes, Proxomo will not only log my application but also take care of logging me into Facebook since Proxomo is designed to be a portal to Facebook and other social network sites.

    So I decided to create a webBrowser custom control to that me or anyone else wanting to log into Proxomo can call from their WP7 app by embedding the control into one of their xaml WP7 pages. Then, when the page containing the custom control is loaded, the Loaded event will navigate to the appropriate url in Proxomo (passing in the login parameters for login in the Querystring). Proxomo will then internally redirect through multiple other pages including Facebook for the user to log into Facebook. When the login process completes, Proxomo directs the browser to a “login result” page that has a specific url and that includes the results of the login operation in its Querystring (cancel, error, success).

    So in the “Navigated” event handler I added code to monitor the url that is being navigated to when it detects that the browser has been asked to display this “login result” page, I will raise an event that I have defined in my browser control so the app can then handle the result properly (like sending the user to some other page in his app).

    Using your example above, I was able to modify it and make it work for me! My understanding is that what I had created was then a USER CONTROL, not a CUSTOM control. One question I have is that now read this article about user controls vs. custom controls:
    http://www.windowsphonegeek.com/articles/User-Control-vs-Custom-Control-in-Silverlight-for-WP7

    and in the Table of Comparisons at the bottom of the article, the 4th comparison says that a USER control does NOT compile into a dll. However, I can see that your example compiles to a dll. So now I am confused, does your example create a User or a Custom control?

    Thanks in advance,

    Hjalmar

  5. Thanks for the post. Do you know how to interact with the Web Browser Control to get the selected word in a navigated page? It seems the single click in IE Mobile will highlight and select a word. But, I cannot get it work in Web Browser control. Do you have any idea about that? Thanks.

  6. is it possilbe to manipulate the text box value served from server on windows phone 7? say i want to post the search string box on http://www.bing.com programattcally.

    webBrowser.Document.forms.. manipulation is possible?

  7. Hi Francisco,
    Thanks for sharing this excellent control. It works fine when i am using the URL bing,google,yahoo etc.But it showing “An unknown error has occurred. Error: 80020006” while using the below URL
    http://m.cvs.com

  8. Hi, nice post, do you know how to navigate to open a link in a browser instead opening it in the webbroser control inside app? Another question: is it possible to play youtube video in webbrowser control?

  9. Great Post! Thanksfor the decisive information. I was wondering the best way to add button functionality to this code sample. For instance, placing buttons in a wp7 application and linking them to correct click events, as well as how to actually display the history (or bind it to a List) if someone wanted to examine previous websites and click on one to navigate to it directly from the history collection? Could u possibly offer some code help on the history navigation, I believe I could take care of the click events myself. Another cool and interesting consideration I thought was to add an optional Favorites category to save sites to a Favorites collection?
    By the way I am new to Windows Phone programming and have grown to love it over the previous month or two of teaching myself. Any descriptive information or links to other websites for help would be greatly appreciated as well!

  10. How to fetch the loaded,navigating url in the textbox after the loadcompleted event occurs in the class library file and how to show the loaded url on the textbox in the main page of application.

  11. Hey Fransisco,
    I am unable to download your source code. I know this post is very old, please do try to help me download your sample.
    I need to implement a web browser in my wp7 application and am facing issues in navigation & downloading files.
    Thanks.

  12. How all… I’ve got the source code but know amount of fiddling with the code seems to get me around the error: An unknown error has occurred. Error: 80020006.

    It seems the assumption that we can can use ‘eval’ isn’t true anymore?

    Anybody have any ideas?

    Dave G

  13. Pretty section of content. I just stumbled upon your site and
    in accession capital to assert that I get in fact enjoyed account your blog posts.

    Anyway I will be subscribing to your feeds and even
    I achievement you access consistently rapidly.

    • Hi francisco,

      I am just learning how to program mobile devices apps. The simple app that i decided to start with is the one that loads a particular website when an app icon is clicked. I succeseded to do it in Android, Iphone & Blackberry.
      How can i do the same using webbrowser control in Windows Phone!!!!!

      I need your help please!

      • Launching a website with the app icon I believe is not supported but what you can do is when you start your app load a web control pointing it to your website, but remember that you have to handle our back button as specified in the post so that you can navigate back in your site.

        Thank You,
        Francisco Fernandez

  14. Definitely believe that which you stated. Your favorite justification seemed to be
    on the net the easiest thing to be aware of. I say to you, I definitely get irked while people consider worries that they plainly do not know about.

    You managed to hit the nail upon the top as well as defined out
    the whole thing without having side-effects , people can take a signal.
    Will likely be back to get more. Thanks

  15. hi!,I like your writing so a lot! share we communicate extra
    approximately your post on AOL? I require a specialist in thks
    space to solve my problem. May be that’s you! Looking ahead to peer you.

  16. Simply wish to say your article is as astonishing.
    The clarity for your publish is simply excellent and that i can assume you’re a professional
    in this subject. Fine together with your permission allow me to seize your
    feed to stay updated with approaching post. Thanks a million and
    please continue the gratifying work.

  17. It’s actually a great and helpful piece of information. I am glad that you simply shared this useful
    information with us. Please stay us up to date like this.
    Thanks for sharing.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s