Chris Pietschmann

husband, father, hacker, entrepreneur, futurist, innovator, autodidact

NAVIGATION - SEARCH

Virtual Earth: Dynamically Load InfoBox Using ASP.NET AJAX

Loading alot of pushpins on the map can slow down your page in two ways: 1) Page load times can be slowed down, and 2) loading pushpins via ajax can be slow. To improve the performance (as in download and database query times) of loading pushpins on the map, you can load the Pushpin Shapes Title and Description on the fly. This allows you to only load the Pushpins Title and Description as it's needed, thus reducing the amount of data you need to send down to the client when initially loading your pushpins.

Dynamically Load InfoBox Title and Description using ASP.NET AJAX

Step 1: When adding Pushpins to the map, use the following format when setting thier Titles: "LOAD:{0}". Replace the "{0}" with a unique ID representing that Pushpin.

var s = new VEShape(VEShapeType.Pushpin, map.GetCenter());
s.Title =
"LOAD:15";
map.AddShape(s);

Step 2: Create the GetInfoBoxData Page Method in the page that we'll call using Ajax. Also create a simple InfoBoxData class in the page; we'll use this class to more easily pass both the Title and Description down to the client.

[WebMethod]
public static InfoBoxData GetInfoBoxData(int id)
{
    // Pass back the InfoBoxData
    InfoBoxData data = new InfoBoxData();
    data.Title =
"Item " + id.ToString();
    // Get the HTML to be displayed within the Description field
    data.Description = ViewManager.RenderView("~/App_Views/InfoBoxDescription.ascx", id);
    return data;
}

Step 3: Add the ViewManager class to the site's App_Code folder. This class will be used within the GetInfoBoxData Page Method to render the Description from a UserControl Template. This class was written by Scott Guthrie in his post titled "Tip/Trick: Cool UI Templating Technique to use with ASP.NET AJAX for non-UpdatePanel scenarios", and it works perfect in this scenario.

public class ViewManager
{
    public static string RenderView(string path)
    {
        return RenderView(path, null);
    }
    public static string RenderView(string path, object data)
    {
        Page pageHolder = new Page();
        UserControl viewControl = (UserControl)pageHolder.LoadControl(path);
        if (data != null)
        {
            Type viewControlType = viewControl.GetType();
            FieldInfo field = viewControlType.GetField("Data");
            if (field != null)
            {
                field.SetValue(viewControl, data);
            }
            else
            {
                throw new Exception("View file: " + path + " does not have a public Data property");
            }
        }
        pageHolder.Controls.Add(viewControl);
        StringWriter output = new StringWriter();
        HttpContext.Current.Server.Execute(pageHolder, output, false);
        return output.ToString();
    }
}

Step 4: Create our InfoBoxDescription UserControl that the GetInfoBoxData Page Method will use as a template for rendering the Description.

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="InfoBoxDescription.ascx.cs" Inherits="App_Views_InfoBoxDescription" %>
This is the description for
<strong>Item <%=this.Data.ToString()%></strong>.<br />
This description was generated dynamically using a UserControl.

public partial class App_Views_InfoBoxDescription : System.Web.UI.UserControl
{
    public int Data;
    protected void Page_Load(object sender, EventArgs e)
    {
    }
}

Step 5:  Attach a JavaScript method to the VE Maps OnMouseMove event, just after the code that instantiates the map.

map.AttachEvent("onmousemove", MapMouseMove);

Step 6: Write code in the OnMouseMove event handler to fire off the GetInfoBoxData Page Method to load the Shapes Title and Description.

function MapMouseMove(e)
{
    if (e.elementID != null)
    {
        var shape = map.GetShapeByID(e.elementID);

        // Check if the Shapes been loaded already
        if (shape.GetTitle().indexOf("LOAD:") != -1)
        {
            // Get our ID for the Shape from within the Shapes Title
            var id = parseInt(shape.GetTitle().substring(5));

            // Set the Shape to display a loading message
            shape.SetTitle("Loading...");

            // Fire off the loading of the InfoBox Data
            PageMethods.GetInfoBoxData(id, /* <-- Pass the WebMethod its parameters */
                InfoBoxDataLoaded, /* <-- The callback method that gets called when the Page Method call Succeeds */
                InfoBoxDataLoadError, /* <-- The callback method that gets called if the Page Method Fails */
                shape /* <-- Pass the Shape as our Context value to the callback method */
            );
        }
    }
}

Step 7: Add our success callback method, that the call to GetInfoBoxData will call once the data has been recieved in the client.

function InfoBoxDataLoaded(result, context, methodName)
{
    var shape = context;
    // Set the Shapes new Title and Description
    shape.SetTitle(result.Title);
    shape.SetDescription(result.Description);
    // Re-Show the InfoBox so the new Title and Description are automatically displayed
    map.ShowInfoBox(shape);
}

Step 8: Add our failure callback method, that the call to GetInfoBoxData will call if it fails.

function InfoBoxDataLoadError(error)
{
    alert(
"Error Occurred Loading InfoBox Data\n" + error.get_message());
}

Conclusion

You'll no longer need to pass the full Title and Description for every Pushpin Shape you plot using this technique. You also be able to save bandwidth, and improve load times in your Virtual Earth implementations.

Download Full Code For This Article Here

blog comments powered by Disqus