Johannes Kebeck's Blog
09-26-2007, 04:13 PM
<p>In the previous parts we added individual VEShape-objects to a layer and*we imported collections from Live Search Maps as well as GeoRSS-feeds. These are quick and simple methods to add information to your map but they are limited to some hundred VEShape-objects. There is no hard cut in Virtual Earth but you will experience a degradation in performance when you have more than let's say 300 points. A good solution would be to not*load all available information but only those which are in the current MapView. Our approach will be to determine the bounding box of the current MapView whenever it changes, use this information to query points of interest from a database and dynamically populate a VEShapeLayer with these points. <p><strong>Dynamically populating*VEShapeLayer from a Database</strong> <p>The Virtual Earth API provides a number of <a href="http://msdn2.microsoft.com/en-us/library/bb412543.aspx">events</a> which we can attach to the map. Amongst these events are such which fire when we <a href="http://msdn2.microsoft.com/en-us/library/bb412469.aspx">finish zooming</a>*or*<a href="http://msdn2.microsoft.com/en-us/library/bb429556.aspx">finish panning</a>. We will capture these events and determine the latitude and longitude of the upper left and the lower right corner*of*our MapView. With these values we will build and execute a SQL-query against a database table with our points of interest (POI) and retrieve only those records which are within our bounding box. To make this as secure as possible we create an AJAX-call*to a WebHandler. The WebHandler in turn will build and execute the SQL Query. While it runs through a SqlDataReader it uses a StringBuilder to dynamically create a JavaScript or JSON-objects. The script is now returned in the response to the AJAX-call and executed there using the eval-command. <p><a href="http://blufiles.storage.msn.com/y1pLfDzppuxash9qdhzxOiTUttgppdg1GyEu0QdXYShtWILiGR 5hErkyIYW-RHOw4_4Q2OPjV3uPc8"><img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px" height=246 alt=image src="http://blufiles.storage.msn.com/y1pLfDzppuxasgcQ-Egz0HDmTevf4mxh-tsxqV4OdOZAysJdr2DqUaik6UdNDjJ9340oosboy_qRZE" width=400 border=0></a> <p>Don't worry, if that was to fast, we will walk through it in slow motion. First we add a new AccordionPane to our web site. Again we have HTML-controls of type checkbox in it and again we will capture the onclick-event and execute a parameterized JavaScript. There are 2 POI-categories we offer so far and that means we have to add 2 checkboxes.<pre><span style="color:rgb(0,0,255)"><</span><span style="color:rgb(163,21,21)">ajaxToolkit</span><span style="color:rgb(0,0,255)">:</span><span style="color:rgb(163,21,21)">AccordionPane</span> <span style="color:rgb(255,0,0)">ID</span><span style="color:rgb(0,0,255)">="panePOI"</span> <span style="color:rgb(255,0,0)">runat</span><span style="color:rgb(0,0,255)">="server">
</span> <span style="color:rgb(0,0,255)"><</span><span style="color:rgb(163,21,21)">Header</span><span style="color:rgb(0,0,255)">></span>POI from Database<span style="color:rgb(0,0,255)"></</span><span style="color:rgb(163,21,21)">Header</span><span style="color:rgb(0,0,255)">>
</span> <span style="color:rgb(0,0,255)"><</span><span style="color:rgb(163,21,21)">Content</span><span style="color:rgb(0,0,255)">>
</span> <span style="color:rgb(0,0,255)"><</span><span style="color:rgb(163,21,21)">input</span> <span style="color:rgb(255,0,0)">id</span><span style="color:rgb(0,0,255)">="cbBP"</span> <span style="color:rgb(255,0,0)">type</span><span style="color:rgb(0,0,255)">="checkbox"</span> <span style="color:rgb(255,0,0)">onclick</span><span style="color:rgb(0,0,255)">="AddPOILayer('cbBP',pplBP)"</span> <span style="color:rgb(0,0,255)">/><</span><span style="color:rgb(163,21,21)">a</span> <span style="color:rgb(255,0,0)">href</span><span style="color:rgb(0,0,255)">='javascript:ShowLocation(51.46160111471333, -0.9252655506134102, 19);'></span>BP<span style="color:rgb(0,0,255)"></</span><span style="color:rgb(163,21,21)">a</span><span style="color:rgb(0,0,255)">><</span><span style="color:rgb(163,21,21)">br</span> <span style="color:rgb(0,0,255)">/></span>
<span style="color:rgb(0,0,255)"><</span><span style="color:rgb(163,21,21)">input</span> <span style="color:rgb(255,0,0)">id</span><span style="color:rgb(0,0,255)">="cbRailway"</span> <span style="color:rgb(255,0,0)">type</span><span style="color:rgb(0,0,255)">="checkbox"</span> <span style="color:rgb(255,0,0)">onclick</span><span style="color:rgb(0,0,255)">="AddPOILayer('cbRailway',pplRailway)"</span> <span style="color:rgb(0,0,255)">/><</span><span style="color:rgb(163,21,21)">a</span> <span style="color:rgb(255,0,0)">href</span><span style="color:rgb(0,0,255)">='javascript:ShowLocation(51.46160111471333, -0.9252655506134102, 19);'></span>Railway<span style="color:rgb(0,0,255)"></</span><span style="color:rgb(163,21,21)">a</span><span style="color:rgb(0,0,255)">><</span><span style="color:rgb(163,21,21)">br</span> <span style="color:rgb(0,0,255)">/></span>
<span style="color:rgb(0,0,255)"></</span><span style="color:rgb(163,21,21)">Content</span><span style="color:rgb(0,0,255)">>
</</span><span style="color:rgb(163,21,21)">ajaxToolkit</span><span style="color:rgb(0,0,255)">:</span><span style="color:rgb(163,21,21)">AccordionPane</span><span style="color:rgb(0,0,255)">>
</span></pre><a href="http://11011.net/software/vspaste"></a>
<p>Now lets move on to the JavaScript-part. In the global section we define an array which holds the activated POI-layers so that we can switch on and off various POI-categories. We also define a VEShapeLayer for each category.<pre><span style="color:rgb(0,0,255)">var</span> activePushPinLayer = <span style="color:rgb(0,0,255)">new</span> Array()
<span style="color:rgb(0,0,255)">var</span> pplBP = <span style="color:rgb(0,0,255)">new</span> VEShapeLayer();
<span style="color:rgb(0,0,255)">var</span> pplRailway = <span style="color:rgb(0,0,255)">new</span> VEShapeLayer();
</pre><a href="http://11011.net/software/vspaste"></a>
<p>In the GetMap-function which is being executed when we load the page we set titles for each layer so that we can easily address them later in our functions.<pre>pplBP.SetTitle(<span style="color:rgb(163,21,21)">'pplBP'</span>);
pplRailway.SetTitle(<span style="color:rgb(163,21,21)">'pplRailway'</span>);</pre><a href="http://11011.net/software/vspaste"></a>
<p>The function that is being executed when we click on one of the checkboxes is AddPOILayer and it takes 2 parameters as input.
<ul>
<li>the name of the control that has been clicked and
<li>the name of the layer we want to populate.</ul>
<p>If*the checkbox has been activated we add the relevant layer to the map and to the array which holds the active VEShapeLayers. Then we attach the events <a href="http://msdn2.microsoft.com/en-us/library/bb429556.aspx">onendpan</a> and <a href="http://msdn2.microsoft.com/en-us/library/bb412469.aspx">onendzoom</a> to the map and make sure that the function LoadData is executed whenever these events occur. Finally we call the function LoadData for the first time.
<p>If the checkbox has been deactivated we leave the layer on the map but we delete all*VEShape-objects from it. Then we remove the VEShapeLayer from the array of active layers and detach the events from the map.<pre><span style="color:rgb(0,0,255)">function</span> AddPOILayer(control,layer)
{
<span style="color:rgb(0,0,255)">if</span> (document.getElementById(control).checked == <span style="color:rgb(0,0,255)">false</span>) {
<span style="color:rgb(0,128,0)">//Delete Shape-Layer
</span> layer.DeleteAllShapes();
<span style="color:rgb(0,128,0)">//Remove the layer from the array of active layers
</span> <span style="color:rgb(0,0,255)">for</span> (<span style="color:rgb(0,0,255)">var</span> i = 0; i < activePushPinLayer.length; ++i)
{
<span style="color:rgb(0,0,255)">if</span> (activePushPinLayer[i] == layer.GetTitle())
{
activePushPinLayer.splice(i,1);
}
}
<span style="color:rgb(0,128,0)">//Detach Map-Events
</span> <span style="color:rgb(0,0,255)">if</span> (activePushPinLayer.length == 1) {
map.DetachEvent(<span style="color:rgb(163,21,21)">"onendpan"</span>, LoadData);
map.DetachEvent(<span style="color:rgb(163,21,21)">"onendzoom"</span>, LoadData);
}
}
<span style="color:rgb(0,0,255)">else</span>{
<span style="color:rgb(0,128,0)">//Create a new Shape-Layer
</span> <span style="color:rgb(0,0,255)">try
</span> {
map.AddShapeLayer(layer);
}
<span style="color:rgb(0,0,255)">catch</span>(e)
{
}
<span style="color:rgb(0,128,0)">//Add the layer to the array of active layers
</span> activePushPinLayer.push(layer.GetTitle());
<span style="color:rgb(0,128,0)">//Attach Map-Events
</span> map.AttachEvent(<span style="color:rgb(163,21,21)">"onendpan"</span>, LoadData);
map.AttachEvent(<span style="color:rgb(163,21,21)">"onendzoom"</span>, LoadData);
LoadData();
}
}</pre><a href="http://11011.net/software/vspaste"></a>
<p>The function LoadData prepares and executes our AJAX-call. First we delete all VEShape-objects from the map. Then we calculate the latitude and longitudes of the upper left and lower right corner of our MapView. Virtual Earth supports us here with a function <a href="http://msdn2.microsoft.com/en-us/library/bb429564.aspx">PixelToLatLong</a>. This function takes as input an VEPixel-object and this again is defined by 2 pixel coordinates relative to the MapView. Thus the upper left corner is always (0, 0) and the lower right corner is defined by the width and the height of our <div>-element. The output of the <a href="http://msdn2.microsoft.com/en-us/library/bb429564.aspx">PixelToLatLong</a>*function is always a VELatLong-object and we need to break it into its properties latitude and longitude.
<p>Now we can start building our AJAX-call. The call goes to a WebHandler DBAccess.ashx which we still have to create and it will hand over a few URL-parameters. The first 4 are always the latitudes and longitudes of the upper left and lower right corner of our MapView. The fifth is the total number of active layers and the next ones are the names of the active layers.
<p>Before we execute the call we first have to determine*what the appropriate XMLHTTP-object for the clients browser is and we do that by calling the function GetXmlHttp. With this object we execute the XMLHTTP Get-Request to our WebHandler and then the call waits until it receives the response from the WehHandler. As mentioned earlier this response is a JavaScript and it will be executed using the eval-command.<pre><span style="color:rgb(0,0,255)">function</span> LoadData()
{
map.DeleteAllShapes();
<span style="color:rgb(0,128,0)">//Retrieve the boundaries of the mapview
</span> <span style="color:rgb(0,0,255)">var</span> ulPixel = <span style="color:rgb(0,0,255)">new</span> VEPixel(0, 0);
<span style="color:rgb(0,0,255)">var</span> brPixel = <span style="color:rgb(0,0,255)">new</span> VEPixel(mapWidth, mapHeight);
<span style="color:rgb(0,0,255)">var</span> ulLatLon = map.PixelToLatcLong(ulPixel);
<span style="color:rgb(0,0,255)">var</span> ulLat = ulLatLon.Latitude;
<span style="color:rgb(0,0,255)">var</span> ulLon = ulLatLon.Longitude;
<span style="color:rgb(0,0,255)">var</span> brLatLon = map.PixelToLatLong(brPixel);
<span style="color:rgb(0,0,255)">var</span> brLat = brLatLon.Latitude;
<span style="color:rgb(0,0,255)">var</span> brLon = brLatLon.Longitude;
<span style="color:rgb(0,128,0)">//Build URL to call the server
</span> <span style="color:rgb(0,0,255)">var</span> url=<span style="color:rgb(163,21,21)">"DBAccess.ashx?"</span>;
url += <span style="color:rgb(163,21,21)">"&ulLat="</span> + ulLat;
url += <span style="color:rgb(163,21,21)">"&ulLon="</span> + ulLon;
url += <span style="color:rgb(163,21,21)">"&brLat="</span> + brLat;
url += <span style="color:rgb(163,21,21)">"&brLon="</span> + brLon;
<span style="color:rgb(0,128,0)">//In this part we check how many and which layers are active
</span> url += <span style="color:rgb(163,21,21)">"&layerCount="</span> + activePushPinLayer.length; <br> <span style="color:rgb(0,0,255)">for</span> (<span style="color:rgb(0,0,255)">var</span> i = 0; i < activePushPinLayer.length; ++i)
{
url += <span style="color:rgb(163,21,21)">"&layer"</span> + i + <span style="color:rgb(163,21,21)">"="</span> + activePushPinLayer[i];
}
<span style="color:rgb(0,128,0)">//Get the appropriate XMLHTTP object for the browser
</span> <span style="color:rgb(0,0,255)">var</span> xmlhttp = GetXmlHttp();
<span style="color:rgb(0,128,0)">//if we have a valid XMLHTTP object
</span> <span style="color:rgb(0,0,255)">if</span> (xmlhttp)
{
xmlhttp.Open(<span style="color:rgb(163,21,21)">"GET"</span>, url, <span style="color:rgb(0,0,255)">true</span>); <span style="color:rgb(0,128,0)">// varAsynx = true
</span>
<span style="color:rgb(0,128,0)">//set the callback
</span> xmlhttp.onreadystatechange = <span style="color:rgb(0,0,255)">function</span>()
{
<span style="color:rgb(0,0,255)">if</span> (xmlhttp.readystate ==4) <span style="color:rgb(0,128,0)">//4 is a success
</span> {
<span style="color:rgb(0,128,0)">//server code creates JavaScript "on the fly" for us to
</span> <span style="color:rgb(0,128,0)">//execute using eval()
</span> <span style="color:rgb(0,0,255)">var</span> result = xmlhttp.responseText
eval(result);
}
}
xmlhttp.send(<span style="color:rgb(0,0,255)">null</span>);
}
}</pre><a href="http://11011.net/software/vspaste"></a>
<p>This is our function to determine the appropriate XMLHTTP-object as mentioned above:<pre><span style="color:rgb(0,0,255)">function</span> GetXmlHttp()
{
<span style="color:rgb(0,0,255)">var</span> x = <span style="color:rgb(0,0,255)">null</span>;
<span style="color:rgb(0,0,255)">try
</span> {
x = <span style="color:rgb(0,0,255)">new</span> ActiveXObject(<span style="color:rgb(163,21,21)">"Msxml2.XMLHTTP"</span>);
}
<span style="color:rgb(0,0,255)">catch</span> (e)
{
<span style="color:rgb(0,0,255)">try
</span> {
x = <span style="color:rgb(0,0,255)">new</span> ActiveXObject(<span style="color:rgb(163,21,21)">"Microsoft.XMLHTTP"</span>);
}
<span style="color:rgb(0,0,255)">catch</span> (e)
{
x = <span style="color:rgb(0,0,255)">null</span>;
}
}
<span style="color:rgb(0,0,255)">if</span> (!x && <span style="color:rgb(0,0,255)">typeof</span> XMLHttpRequest != <span style="color:rgb(163,21,21)">"undefined"</span>)
{
x = <span style="color:rgb(0,0,255)">new</span> XMLHttpRequest();
}
<span style="color:rgb(0,0,255)">return</span> x;
}
</pre><a href="http://11011.net/software/vspaste"></a>
<p>That's all on the JavaScript side. Now we move on to our WebHandler but before we do that let's have a quick look at our database. We have 2 tables for the POI with a total of more than 4,000 records. The tables contain columns for the latitude and longitude and one with the same. This is of course just a sample and there could be many more information in it. How did we get the latitudes and longitudes in the first place? Well, that may be an issue for another blog-posting but the Virtual Earth platform can support you here as well.<pre><span style="color:rgb(0,0,255)">CREATE</span> <span style="color:rgb(0,0,255)">TABLE</span> [BP]<span style="color:rgb(128,128,128)">(
</span> [Latitude] [float]<span style="color:rgb(128,128,128)">,
</span> [Longitude] [float]<span style="color:rgb(128,128,128)">,
</span> [Name] [nvarchar]<span style="color:rgb(128,128,128)">(</span>255<span style="color:rgb(128,128,128)">))</span></pre><a href="http://11011.net/software/vspaste"></a>
<p>We define the connection string to our database in the web.config<pre><span style="color:rgb(0,0,255)"><</span><span style="color:rgb(163,21,21)">connectionStrings</span><span style="color:rgb(0,0,255)">>
<</span><span style="color:rgb(163,21,21)">add</span><span style="color:rgb(0,0,255)"> </span><span style="color:rgb(255,0,0)">name</span><span style="color:rgb(0,0,255)">=</span>"<span style="color:rgb(0,0,255)">MyDB</span>"
<span style="color:rgb(0,0,255)"> </span><span style="color:rgb(255,0,0)">connectionString</span><span style="color:rgb(0,0,255)">=</span>"
<span style="color:rgb(0,0,255)"> Data Source=MyServer;
Initial Catalog=MyDatabase;
uid=MyUID; pwd=MyPWD;</span>"
<span style="color:rgb(0,0,255)"> </span><span style="color:rgb(255,0,0)">providerName</span><span style="color:rgb(0,0,255)">=</span>"<span style="color:rgb(0,0,255)">System.Data.SqlClient</span>"<span style="color:rgb(0,0,255)">/>
</</span><span style="color:rgb(163,21,21)">connectionStrings</span><span style="color:rgb(0,0,255)">>
</span></pre><a href="http://11011.net/software/vspaste"></a>
<p>Now we create a new WebHandler DBAccess.ashx and import the namespace<pre><span style="color:rgb(0,0,255)">Imports</span> System.Data.SqlClient</pre><a href="http://11011.net/software/vspaste"></a>
<p>Finally we replace the default code with the one shown below. It is always a good idea to set the CurrentCulture to make sure that the decimal separator for the latitudes and *longitudes are returned as a '.'. Then we fetch the URL-parameters as well as the ConnectionStrings from the web.config and set up the database connection before we build the SqlCommand. The SqlCommand is being executed with a SqlDataReader and as we read the records we use a StringBuilder to create the JavaScript which is later to be returned to the AJAX-call and executed there. If we have more than 300 records which meet the criteria we don't return a JavaScript to add the VEShape-objects but rather we return a script which pops up a message. <pre><span style="color:rgb(0,128,0)">'set culture to en-UK to avoid potential problems with decimal-separators
</span>System.Threading.Thread.CurrentThread.CurrentCultu re = System.Globalization.CultureInfo.CreateSpecificCul ture(<span style="color:rgb(163,21,21)">"en-UK"</span>)
<span style="color:rgb(0,128,0)">'Get the URL-Parameters
</span><span style="color:rgb(0,0,255)">Dim</span> ulLat <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = context.Request.Params(<span style="color:rgb(163,21,21)">"ulLat"</span>)
<span style="color:rgb(0,0,255)">Dim</span> brLat <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = context.Request.Params(<span style="color:rgb(163,21,21)">"brLat"</span>)
<span style="color:rgb(0,0,255)">Dim</span> ulLon <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = context.Request.Params(<span style="color:rgb(163,21,21)">"ulLon"</span>)
<span style="color:rgb(0,0,255)">Dim</span> brLon <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = context.Request.Params(<span style="color:rgb(163,21,21)">"brLon"</span>)
<span style="color:rgb(0,128,0)">'How many layers are active?
</span><span style="color:rgb(0,0,255)">Dim</span> layerCount <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">Integer</span> = context.Request.Params(<span style="color:rgb(163,21,21)">"layerCount"</span>)
<span style="color:rgb(0,128,0)">'Query database(s) and create JavaScript
</span><span style="color:rgb(0,0,255)">Dim</span> settings <span style="color:rgb(0,0,255)">As</span> ConnectionStringSettings
<span style="color:rgb(0,0,255)">Dim</span> sb <span style="color:rgb(0,0,255)">As</span> StringBuilder = <span style="color:rgb(0,0,255)">New</span> StringBuilder
<span style="color:rgb(0,0,255)">Dim</span> myPins <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = <span style="color:rgb(163,21,21)">""
</span><span style="color:rgb(0,0,255)">Dim</span> poiCounter <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">Integer</span> = 0
<span style="color:rgb(0,0,255)">Dim</span> i <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">Integer</span> = 0
<span style="color:rgb(0,0,255)">For</span> i = 0 <span style="color:rgb(0,0,255)">To</span> layerCount
<span style="color:rgb(0,0,255)">Dim</span> dummy <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = context.Request.Params(<span style="color:rgb(163,21,21)">"layer"</span> & i)
<span style="color:rgb(0,0,255)">Select</span> <span style="color:rgb(0,0,255)">Case</span> dummy
<span style="color:rgb(0,0,255)">Case</span> <span style="color:rgb(163,21,21)">"pplBP"
</span> settings = ConfigurationManager.ConnectionStrings(<span style="color:rgb(163,21,21)">"MyDB"</span>)
<span style="color:rgb(0,0,255)">Dim</span> myConn <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">New</span> SqlConnection(settings.ConnectionString)
<span style="color:rgb(0,0,255)">Dim</span> myQuery1 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = <span style="color:rgb(163,21,21)">"SELECT COUNT(*) FROM BP WHERE (Latitude BETWEEN "</span> + brLat + <span style="color:rgb(163,21,21)">" AND "</span> + ulLat + <span style="color:rgb(163,21,21)">") AND (Longitude BETWEEN "</span> + ulLon + <span style="color:rgb(163,21,21)">" AND "</span> + brLon + <span style="color:rgb(163,21,21)">")"
</span> <span style="color:rgb(0,0,255)">Dim</span> myCMD1 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">New</span> SqlCommand(myQuery1, myConn)
myConn.Open()
<span style="color:rgb(0,0,255)">Dim</span> myReader1 <span style="color:rgb(0,0,255)">As</span> SqlDataReader = myCMD1.ExecuteReader()
myReader1.Read()
<span style="color:rgb(0,0,255)">If</span> myReader1(0) > 300 <span style="color:rgb(0,0,255)">Then
</span> myPins = myPins + _
<span style="color:rgb(163,21,21)">"map.ShowMessage('There are more than 300s POI of type BP in this MapView. The Layer will not be shown.');"
</span> sb.Append(myPins)
myReader1.Close()
<span style="color:rgb(0,0,255)">Else
</span> poiCounter = poiCounter + myReader1(0)
myReader1.Close()
<span style="color:rgb(0,0,255)">Dim</span> j <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">Integer</span> = 0
<span style="color:rgb(0,0,255)">Dim</span> myQuery2 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = <span style="color:rgb(163,21,21)">"SELECT Latitude, Longitude, Name FROM BP WHERE (Latitude BETWEEN "</span> + brLat + <span style="color:rgb(163,21,21)">" AND "</span> + ulLat + <span style="color:rgb(163,21,21)">") AND (Longitude BETWEEN "</span> + ulLon + <span style="color:rgb(163,21,21)">" AND "</span> + brLon + <span style="color:rgb(163,21,21)">")"
</span> <span style="color:rgb(0,0,255)">Dim</span> myCMD2 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">New</span> SqlCommand(myQuery2, myConn)
<span style="color:rgb(0,0,255)">Dim</span> myReader2 <span style="color:rgb(0,0,255)">As</span> SqlDataReader = myCMD2.ExecuteReader()
<span style="color:rgb(0,0,255)">While</span> myReader2.Read()
myPins = myPins + _
<span style="color:rgb(163,21,21)">"var shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">"=new VEShape(VEShapeType.Pushpin, new VELatLong("</span> + myReader2(0).ToString + <span style="color:rgb(163,21,21)">", "</span> + myReader2(1).ToString + <span style="color:rgb(163,21,21)">"));"</span> + _
<span style="color:rgb(163,21,21)">"shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">".SetCustomIcon('IMG/BP.bmp');"</span> + _
<span style="color:rgb(163,21,21)">"shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">".SetTitle("</span> + <span style="color:rgb(163,21,21)">""""</span> + myReader2(2).ToString + <span style="color:rgb(163,21,21)">""""</span> + <span style="color:rgb(163,21,21)">");"</span> + _
<span style="color:rgb(163,21,21)">"pplBP.AddShape(shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">");"
</span> j = j + 1
<span style="color:rgb(0,0,255)">End</span> <span style="color:rgb(0,0,255)">While
</span> sb.Append(myPins)
myReader2.Close()
<span style="color:rgb(0,0,255)">End</span> <span style="color:rgb(0,0,255)">If
</span> myConn.Close()
<span style="color:rgb(0,0,255)">Case</span> <span style="color:rgb(163,21,21)">"pplRailway"
</span> settings = ConfigurationManager.ConnectionStrings(<span style="color:rgb(163,21,21)">"MyDB"</span>)
<span style="color:rgb(0,0,255)">Dim</span> myConn <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">New</span> SqlConnection(settings.ConnectionString)
<span style="color:rgb(0,0,255)">Dim</span> myQuery1 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = <span style="color:rgb(163,21,21)">"SELECT COUNT(*) FROM Railway WHERE (Latitude BETWEEN "</span> + brLat + <span style="color:rgb(163,21,21)">" AND "</span> + ulLat + <span style="color:rgb(163,21,21)">") AND (Longitude BETWEEN "</span> + ulLon + <span style="color:rgb(163,21,21)">" AND "</span> + brLon + <span style="color:rgb(163,21,21)">")"
</span> <span style="color:rgb(0,0,255)">Dim</span> myCMD1 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">New</span> SqlCommand(myQuery1, myConn)
myConn.Open()
<span style="color:rgb(0,0,255)">Dim</span> myReader1 <span style="color:rgb(0,0,255)">As</span> SqlDataReader = myCMD1.ExecuteReader()
myReader1.Read()
<span style="color:rgb(0,0,255)">If</span> myReader1(0) > 300 <span style="color:rgb(0,0,255)">Then
</span> myPins = myPins + _
<span style="color:rgb(163,21,21)">"map.ShowMessage('There are more than 300s POI of type Railway in this MapView. The Layer will not be shown.');"
</span> sb.Append(myPins)
myReader1.Close()
<span style="color:rgb(0,0,255)">Else
</span> poiCounter = poiCounter + myReader1(0)
myReader1.Close()
<span style="color:rgb(0,0,255)">Dim</span> j <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">Integer</span> = 0
<span style="color:rgb(0,0,255)">Dim</span> myQuery2 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = <span style="color:rgb(163,21,21)">"SELECT Latitude, Longitude, Name FROM Railway WHERE (Latitude BETWEEN "</span> + brLat + <span style="color:rgb(163,21,21)">" AND "</span> + ulLat + <span style="color:rgb(163,21,21)">") AND (Longitude BETWEEN "</span> + ulLon + <span style="color:rgb(163,21,21)">" AND "</span> + brLon + <span style="color:rgb(163,21,21)">")"
</span> <span style="color:rgb(0,0,255)">Dim</span> myCMD2 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">New</span> SqlCommand(myQuery2, myConn)
<span style="color:rgb(0,0,255)">Dim</span> myReader2 <span style="color:rgb(0,0,255)">As</span> SqlDataReader = myCMD2.ExecuteReader()
<span style="color:rgb(0,0,255)">While</span> myReader2.Read()
myPins = myPins + _
<span style="color:rgb(163,21,21)">"var shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">"=new VEShape(VEShapeType.Pushpin, new VELatLong("</span> + myReader2(0).ToString + <span style="color:rgb(163,21,21)">", "</span> + myReader2(1).ToString + <span style="color:rgb(163,21,21)">"));"</span> + _
<span style="color:rgb(163,21,21)">"shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">".SetCustomIcon('IMG/Railway.bmp');"</span> + _
<span style="color:rgb(163,21,21)">"shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">".SetTitle("</span> + <span style="color:rgb(163,21,21)">""""</span> + myReader2(2).ToString + <span style="color:rgb(163,21,21)">""""</span> + <span style="color:rgb(163,21,21)">");"</span> + _
<span style="color:rgb(163,21,21)">"pplRailway.AddShape(shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">");"
</span> j = j + 1
<span style="color:rgb(0,0,255)">End</span> <span style="color:rgb(0,0,255)">While
</span> sb.Append(myPins)
myReader2.Close()
<span style="color:rgb(0,0,255)">End</span> <span style="color:rgb(0,0,255)">If
</span> myConn.Close()
<span style="color:rgb(0,0,255)">End</span> <span style="color:rgb(0,0,255)">Select
</span><span style="color:rgb(0,0,255)">Next
</span><span style="color:rgb(0,0,255)">If</span> poiCounter > 300 <span style="color:rgb(0,0,255)">Then
</span> context.Response.Write(<span style="color:rgb(163,21,21)">"map.ShowMessage('The POIs in all layers add up to more than 300. Please deselect a layer or zoom-in.');"</span>)
<span style="color:rgb(0,0,255)">Else
</span> context.Response.Write(sb.ToString())
<span style="color:rgb(0,0,255)">End</span> <span style="color:rgb(0,0,255)">If</span></pre><a href="http://11011.net/software/vspaste"></a>
<p>All right, that's it let's see what we have:
<p><a href="http://blufiles.storage.msn.com/y1pLfDzppuxasiciUZid3mSWNPU-zf-2_jrz21ZYYiaTUHl4_h4r_x98ua777iwecfzFKiUdPdSd3Q"><img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px" alt=14-small src="http://blufiles.storage.msn.com/y1pLfDzppuxashpLb4j48_NVtCbJWMl7NaFGWJ6BjVn6HW2wmW LHCxQY0pNX1uud30WwpYyi67dKlk" border=0></a>
<p>You will find the sample application <a href="http://mappointemea.members.winisp.net/Database/Default.aspx">here</a> and as always the complete source code is available for download from this page as well.
<div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px">Technorati Tags: <a href="http://technorati.com/tags/Virtual Earth" rel=tag>Virtual Earth</a>, <a href="http://technorati.com/tags/AJAX" rel=tag>AJAX</a>, <a href="http://technorati.com/tags/Database" rel=tag>Database</a></div><img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=4819404664324524694&page=RSS%3a+How+to+bring+your+own+content+to+Virtu al+Earth+(Part+4)&referrer=" width="1px" height="1px" border="0" alt=""><img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&NA=1149&PI=88469&RF=&DI=3919&PS=85545&TP=johanneskebeck.spaces.live.com>1=JohannesKebeck">
Click here to view the article. (http://JohannesKebeck.spaces.live.com/Blog/cns!42E1F70205EC8A96!1822.entry)
</span> <span style="color:rgb(0,0,255)"><</span><span style="color:rgb(163,21,21)">Header</span><span style="color:rgb(0,0,255)">></span>POI from Database<span style="color:rgb(0,0,255)"></</span><span style="color:rgb(163,21,21)">Header</span><span style="color:rgb(0,0,255)">>
</span> <span style="color:rgb(0,0,255)"><</span><span style="color:rgb(163,21,21)">Content</span><span style="color:rgb(0,0,255)">>
</span> <span style="color:rgb(0,0,255)"><</span><span style="color:rgb(163,21,21)">input</span> <span style="color:rgb(255,0,0)">id</span><span style="color:rgb(0,0,255)">="cbBP"</span> <span style="color:rgb(255,0,0)">type</span><span style="color:rgb(0,0,255)">="checkbox"</span> <span style="color:rgb(255,0,0)">onclick</span><span style="color:rgb(0,0,255)">="AddPOILayer('cbBP',pplBP)"</span> <span style="color:rgb(0,0,255)">/><</span><span style="color:rgb(163,21,21)">a</span> <span style="color:rgb(255,0,0)">href</span><span style="color:rgb(0,0,255)">='javascript:ShowLocation(51.46160111471333, -0.9252655506134102, 19);'></span>BP<span style="color:rgb(0,0,255)"></</span><span style="color:rgb(163,21,21)">a</span><span style="color:rgb(0,0,255)">><</span><span style="color:rgb(163,21,21)">br</span> <span style="color:rgb(0,0,255)">/></span>
<span style="color:rgb(0,0,255)"><</span><span style="color:rgb(163,21,21)">input</span> <span style="color:rgb(255,0,0)">id</span><span style="color:rgb(0,0,255)">="cbRailway"</span> <span style="color:rgb(255,0,0)">type</span><span style="color:rgb(0,0,255)">="checkbox"</span> <span style="color:rgb(255,0,0)">onclick</span><span style="color:rgb(0,0,255)">="AddPOILayer('cbRailway',pplRailway)"</span> <span style="color:rgb(0,0,255)">/><</span><span style="color:rgb(163,21,21)">a</span> <span style="color:rgb(255,0,0)">href</span><span style="color:rgb(0,0,255)">='javascript:ShowLocation(51.46160111471333, -0.9252655506134102, 19);'></span>Railway<span style="color:rgb(0,0,255)"></</span><span style="color:rgb(163,21,21)">a</span><span style="color:rgb(0,0,255)">><</span><span style="color:rgb(163,21,21)">br</span> <span style="color:rgb(0,0,255)">/></span>
<span style="color:rgb(0,0,255)"></</span><span style="color:rgb(163,21,21)">Content</span><span style="color:rgb(0,0,255)">>
</</span><span style="color:rgb(163,21,21)">ajaxToolkit</span><span style="color:rgb(0,0,255)">:</span><span style="color:rgb(163,21,21)">AccordionPane</span><span style="color:rgb(0,0,255)">>
</span></pre><a href="http://11011.net/software/vspaste"></a>
<p>Now lets move on to the JavaScript-part. In the global section we define an array which holds the activated POI-layers so that we can switch on and off various POI-categories. We also define a VEShapeLayer for each category.<pre><span style="color:rgb(0,0,255)">var</span> activePushPinLayer = <span style="color:rgb(0,0,255)">new</span> Array()
<span style="color:rgb(0,0,255)">var</span> pplBP = <span style="color:rgb(0,0,255)">new</span> VEShapeLayer();
<span style="color:rgb(0,0,255)">var</span> pplRailway = <span style="color:rgb(0,0,255)">new</span> VEShapeLayer();
</pre><a href="http://11011.net/software/vspaste"></a>
<p>In the GetMap-function which is being executed when we load the page we set titles for each layer so that we can easily address them later in our functions.<pre>pplBP.SetTitle(<span style="color:rgb(163,21,21)">'pplBP'</span>);
pplRailway.SetTitle(<span style="color:rgb(163,21,21)">'pplRailway'</span>);</pre><a href="http://11011.net/software/vspaste"></a>
<p>The function that is being executed when we click on one of the checkboxes is AddPOILayer and it takes 2 parameters as input.
<ul>
<li>the name of the control that has been clicked and
<li>the name of the layer we want to populate.</ul>
<p>If*the checkbox has been activated we add the relevant layer to the map and to the array which holds the active VEShapeLayers. Then we attach the events <a href="http://msdn2.microsoft.com/en-us/library/bb429556.aspx">onendpan</a> and <a href="http://msdn2.microsoft.com/en-us/library/bb412469.aspx">onendzoom</a> to the map and make sure that the function LoadData is executed whenever these events occur. Finally we call the function LoadData for the first time.
<p>If the checkbox has been deactivated we leave the layer on the map but we delete all*VEShape-objects from it. Then we remove the VEShapeLayer from the array of active layers and detach the events from the map.<pre><span style="color:rgb(0,0,255)">function</span> AddPOILayer(control,layer)
{
<span style="color:rgb(0,0,255)">if</span> (document.getElementById(control).checked == <span style="color:rgb(0,0,255)">false</span>) {
<span style="color:rgb(0,128,0)">//Delete Shape-Layer
</span> layer.DeleteAllShapes();
<span style="color:rgb(0,128,0)">//Remove the layer from the array of active layers
</span> <span style="color:rgb(0,0,255)">for</span> (<span style="color:rgb(0,0,255)">var</span> i = 0; i < activePushPinLayer.length; ++i)
{
<span style="color:rgb(0,0,255)">if</span> (activePushPinLayer[i] == layer.GetTitle())
{
activePushPinLayer.splice(i,1);
}
}
<span style="color:rgb(0,128,0)">//Detach Map-Events
</span> <span style="color:rgb(0,0,255)">if</span> (activePushPinLayer.length == 1) {
map.DetachEvent(<span style="color:rgb(163,21,21)">"onendpan"</span>, LoadData);
map.DetachEvent(<span style="color:rgb(163,21,21)">"onendzoom"</span>, LoadData);
}
}
<span style="color:rgb(0,0,255)">else</span>{
<span style="color:rgb(0,128,0)">//Create a new Shape-Layer
</span> <span style="color:rgb(0,0,255)">try
</span> {
map.AddShapeLayer(layer);
}
<span style="color:rgb(0,0,255)">catch</span>(e)
{
}
<span style="color:rgb(0,128,0)">//Add the layer to the array of active layers
</span> activePushPinLayer.push(layer.GetTitle());
<span style="color:rgb(0,128,0)">//Attach Map-Events
</span> map.AttachEvent(<span style="color:rgb(163,21,21)">"onendpan"</span>, LoadData);
map.AttachEvent(<span style="color:rgb(163,21,21)">"onendzoom"</span>, LoadData);
LoadData();
}
}</pre><a href="http://11011.net/software/vspaste"></a>
<p>The function LoadData prepares and executes our AJAX-call. First we delete all VEShape-objects from the map. Then we calculate the latitude and longitudes of the upper left and lower right corner of our MapView. Virtual Earth supports us here with a function <a href="http://msdn2.microsoft.com/en-us/library/bb429564.aspx">PixelToLatLong</a>. This function takes as input an VEPixel-object and this again is defined by 2 pixel coordinates relative to the MapView. Thus the upper left corner is always (0, 0) and the lower right corner is defined by the width and the height of our <div>-element. The output of the <a href="http://msdn2.microsoft.com/en-us/library/bb429564.aspx">PixelToLatLong</a>*function is always a VELatLong-object and we need to break it into its properties latitude and longitude.
<p>Now we can start building our AJAX-call. The call goes to a WebHandler DBAccess.ashx which we still have to create and it will hand over a few URL-parameters. The first 4 are always the latitudes and longitudes of the upper left and lower right corner of our MapView. The fifth is the total number of active layers and the next ones are the names of the active layers.
<p>Before we execute the call we first have to determine*what the appropriate XMLHTTP-object for the clients browser is and we do that by calling the function GetXmlHttp. With this object we execute the XMLHTTP Get-Request to our WebHandler and then the call waits until it receives the response from the WehHandler. As mentioned earlier this response is a JavaScript and it will be executed using the eval-command.<pre><span style="color:rgb(0,0,255)">function</span> LoadData()
{
map.DeleteAllShapes();
<span style="color:rgb(0,128,0)">//Retrieve the boundaries of the mapview
</span> <span style="color:rgb(0,0,255)">var</span> ulPixel = <span style="color:rgb(0,0,255)">new</span> VEPixel(0, 0);
<span style="color:rgb(0,0,255)">var</span> brPixel = <span style="color:rgb(0,0,255)">new</span> VEPixel(mapWidth, mapHeight);
<span style="color:rgb(0,0,255)">var</span> ulLatLon = map.PixelToLatcLong(ulPixel);
<span style="color:rgb(0,0,255)">var</span> ulLat = ulLatLon.Latitude;
<span style="color:rgb(0,0,255)">var</span> ulLon = ulLatLon.Longitude;
<span style="color:rgb(0,0,255)">var</span> brLatLon = map.PixelToLatLong(brPixel);
<span style="color:rgb(0,0,255)">var</span> brLat = brLatLon.Latitude;
<span style="color:rgb(0,0,255)">var</span> brLon = brLatLon.Longitude;
<span style="color:rgb(0,128,0)">//Build URL to call the server
</span> <span style="color:rgb(0,0,255)">var</span> url=<span style="color:rgb(163,21,21)">"DBAccess.ashx?"</span>;
url += <span style="color:rgb(163,21,21)">"&ulLat="</span> + ulLat;
url += <span style="color:rgb(163,21,21)">"&ulLon="</span> + ulLon;
url += <span style="color:rgb(163,21,21)">"&brLat="</span> + brLat;
url += <span style="color:rgb(163,21,21)">"&brLon="</span> + brLon;
<span style="color:rgb(0,128,0)">//In this part we check how many and which layers are active
</span> url += <span style="color:rgb(163,21,21)">"&layerCount="</span> + activePushPinLayer.length; <br> <span style="color:rgb(0,0,255)">for</span> (<span style="color:rgb(0,0,255)">var</span> i = 0; i < activePushPinLayer.length; ++i)
{
url += <span style="color:rgb(163,21,21)">"&layer"</span> + i + <span style="color:rgb(163,21,21)">"="</span> + activePushPinLayer[i];
}
<span style="color:rgb(0,128,0)">//Get the appropriate XMLHTTP object for the browser
</span> <span style="color:rgb(0,0,255)">var</span> xmlhttp = GetXmlHttp();
<span style="color:rgb(0,128,0)">//if we have a valid XMLHTTP object
</span> <span style="color:rgb(0,0,255)">if</span> (xmlhttp)
{
xmlhttp.Open(<span style="color:rgb(163,21,21)">"GET"</span>, url, <span style="color:rgb(0,0,255)">true</span>); <span style="color:rgb(0,128,0)">// varAsynx = true
</span>
<span style="color:rgb(0,128,0)">//set the callback
</span> xmlhttp.onreadystatechange = <span style="color:rgb(0,0,255)">function</span>()
{
<span style="color:rgb(0,0,255)">if</span> (xmlhttp.readystate ==4) <span style="color:rgb(0,128,0)">//4 is a success
</span> {
<span style="color:rgb(0,128,0)">//server code creates JavaScript "on the fly" for us to
</span> <span style="color:rgb(0,128,0)">//execute using eval()
</span> <span style="color:rgb(0,0,255)">var</span> result = xmlhttp.responseText
eval(result);
}
}
xmlhttp.send(<span style="color:rgb(0,0,255)">null</span>);
}
}</pre><a href="http://11011.net/software/vspaste"></a>
<p>This is our function to determine the appropriate XMLHTTP-object as mentioned above:<pre><span style="color:rgb(0,0,255)">function</span> GetXmlHttp()
{
<span style="color:rgb(0,0,255)">var</span> x = <span style="color:rgb(0,0,255)">null</span>;
<span style="color:rgb(0,0,255)">try
</span> {
x = <span style="color:rgb(0,0,255)">new</span> ActiveXObject(<span style="color:rgb(163,21,21)">"Msxml2.XMLHTTP"</span>);
}
<span style="color:rgb(0,0,255)">catch</span> (e)
{
<span style="color:rgb(0,0,255)">try
</span> {
x = <span style="color:rgb(0,0,255)">new</span> ActiveXObject(<span style="color:rgb(163,21,21)">"Microsoft.XMLHTTP"</span>);
}
<span style="color:rgb(0,0,255)">catch</span> (e)
{
x = <span style="color:rgb(0,0,255)">null</span>;
}
}
<span style="color:rgb(0,0,255)">if</span> (!x && <span style="color:rgb(0,0,255)">typeof</span> XMLHttpRequest != <span style="color:rgb(163,21,21)">"undefined"</span>)
{
x = <span style="color:rgb(0,0,255)">new</span> XMLHttpRequest();
}
<span style="color:rgb(0,0,255)">return</span> x;
}
</pre><a href="http://11011.net/software/vspaste"></a>
<p>That's all on the JavaScript side. Now we move on to our WebHandler but before we do that let's have a quick look at our database. We have 2 tables for the POI with a total of more than 4,000 records. The tables contain columns for the latitude and longitude and one with the same. This is of course just a sample and there could be many more information in it. How did we get the latitudes and longitudes in the first place? Well, that may be an issue for another blog-posting but the Virtual Earth platform can support you here as well.<pre><span style="color:rgb(0,0,255)">CREATE</span> <span style="color:rgb(0,0,255)">TABLE</span> [BP]<span style="color:rgb(128,128,128)">(
</span> [Latitude] [float]<span style="color:rgb(128,128,128)">,
</span> [Longitude] [float]<span style="color:rgb(128,128,128)">,
</span> [Name] [nvarchar]<span style="color:rgb(128,128,128)">(</span>255<span style="color:rgb(128,128,128)">))</span></pre><a href="http://11011.net/software/vspaste"></a>
<p>We define the connection string to our database in the web.config<pre><span style="color:rgb(0,0,255)"><</span><span style="color:rgb(163,21,21)">connectionStrings</span><span style="color:rgb(0,0,255)">>
<</span><span style="color:rgb(163,21,21)">add</span><span style="color:rgb(0,0,255)"> </span><span style="color:rgb(255,0,0)">name</span><span style="color:rgb(0,0,255)">=</span>"<span style="color:rgb(0,0,255)">MyDB</span>"
<span style="color:rgb(0,0,255)"> </span><span style="color:rgb(255,0,0)">connectionString</span><span style="color:rgb(0,0,255)">=</span>"
<span style="color:rgb(0,0,255)"> Data Source=MyServer;
Initial Catalog=MyDatabase;
uid=MyUID; pwd=MyPWD;</span>"
<span style="color:rgb(0,0,255)"> </span><span style="color:rgb(255,0,0)">providerName</span><span style="color:rgb(0,0,255)">=</span>"<span style="color:rgb(0,0,255)">System.Data.SqlClient</span>"<span style="color:rgb(0,0,255)">/>
</</span><span style="color:rgb(163,21,21)">connectionStrings</span><span style="color:rgb(0,0,255)">>
</span></pre><a href="http://11011.net/software/vspaste"></a>
<p>Now we create a new WebHandler DBAccess.ashx and import the namespace<pre><span style="color:rgb(0,0,255)">Imports</span> System.Data.SqlClient</pre><a href="http://11011.net/software/vspaste"></a>
<p>Finally we replace the default code with the one shown below. It is always a good idea to set the CurrentCulture to make sure that the decimal separator for the latitudes and *longitudes are returned as a '.'. Then we fetch the URL-parameters as well as the ConnectionStrings from the web.config and set up the database connection before we build the SqlCommand. The SqlCommand is being executed with a SqlDataReader and as we read the records we use a StringBuilder to create the JavaScript which is later to be returned to the AJAX-call and executed there. If we have more than 300 records which meet the criteria we don't return a JavaScript to add the VEShape-objects but rather we return a script which pops up a message. <pre><span style="color:rgb(0,128,0)">'set culture to en-UK to avoid potential problems with decimal-separators
</span>System.Threading.Thread.CurrentThread.CurrentCultu re = System.Globalization.CultureInfo.CreateSpecificCul ture(<span style="color:rgb(163,21,21)">"en-UK"</span>)
<span style="color:rgb(0,128,0)">'Get the URL-Parameters
</span><span style="color:rgb(0,0,255)">Dim</span> ulLat <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = context.Request.Params(<span style="color:rgb(163,21,21)">"ulLat"</span>)
<span style="color:rgb(0,0,255)">Dim</span> brLat <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = context.Request.Params(<span style="color:rgb(163,21,21)">"brLat"</span>)
<span style="color:rgb(0,0,255)">Dim</span> ulLon <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = context.Request.Params(<span style="color:rgb(163,21,21)">"ulLon"</span>)
<span style="color:rgb(0,0,255)">Dim</span> brLon <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = context.Request.Params(<span style="color:rgb(163,21,21)">"brLon"</span>)
<span style="color:rgb(0,128,0)">'How many layers are active?
</span><span style="color:rgb(0,0,255)">Dim</span> layerCount <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">Integer</span> = context.Request.Params(<span style="color:rgb(163,21,21)">"layerCount"</span>)
<span style="color:rgb(0,128,0)">'Query database(s) and create JavaScript
</span><span style="color:rgb(0,0,255)">Dim</span> settings <span style="color:rgb(0,0,255)">As</span> ConnectionStringSettings
<span style="color:rgb(0,0,255)">Dim</span> sb <span style="color:rgb(0,0,255)">As</span> StringBuilder = <span style="color:rgb(0,0,255)">New</span> StringBuilder
<span style="color:rgb(0,0,255)">Dim</span> myPins <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = <span style="color:rgb(163,21,21)">""
</span><span style="color:rgb(0,0,255)">Dim</span> poiCounter <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">Integer</span> = 0
<span style="color:rgb(0,0,255)">Dim</span> i <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">Integer</span> = 0
<span style="color:rgb(0,0,255)">For</span> i = 0 <span style="color:rgb(0,0,255)">To</span> layerCount
<span style="color:rgb(0,0,255)">Dim</span> dummy <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = context.Request.Params(<span style="color:rgb(163,21,21)">"layer"</span> & i)
<span style="color:rgb(0,0,255)">Select</span> <span style="color:rgb(0,0,255)">Case</span> dummy
<span style="color:rgb(0,0,255)">Case</span> <span style="color:rgb(163,21,21)">"pplBP"
</span> settings = ConfigurationManager.ConnectionStrings(<span style="color:rgb(163,21,21)">"MyDB"</span>)
<span style="color:rgb(0,0,255)">Dim</span> myConn <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">New</span> SqlConnection(settings.ConnectionString)
<span style="color:rgb(0,0,255)">Dim</span> myQuery1 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = <span style="color:rgb(163,21,21)">"SELECT COUNT(*) FROM BP WHERE (Latitude BETWEEN "</span> + brLat + <span style="color:rgb(163,21,21)">" AND "</span> + ulLat + <span style="color:rgb(163,21,21)">") AND (Longitude BETWEEN "</span> + ulLon + <span style="color:rgb(163,21,21)">" AND "</span> + brLon + <span style="color:rgb(163,21,21)">")"
</span> <span style="color:rgb(0,0,255)">Dim</span> myCMD1 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">New</span> SqlCommand(myQuery1, myConn)
myConn.Open()
<span style="color:rgb(0,0,255)">Dim</span> myReader1 <span style="color:rgb(0,0,255)">As</span> SqlDataReader = myCMD1.ExecuteReader()
myReader1.Read()
<span style="color:rgb(0,0,255)">If</span> myReader1(0) > 300 <span style="color:rgb(0,0,255)">Then
</span> myPins = myPins + _
<span style="color:rgb(163,21,21)">"map.ShowMessage('There are more than 300s POI of type BP in this MapView. The Layer will not be shown.');"
</span> sb.Append(myPins)
myReader1.Close()
<span style="color:rgb(0,0,255)">Else
</span> poiCounter = poiCounter + myReader1(0)
myReader1.Close()
<span style="color:rgb(0,0,255)">Dim</span> j <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">Integer</span> = 0
<span style="color:rgb(0,0,255)">Dim</span> myQuery2 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = <span style="color:rgb(163,21,21)">"SELECT Latitude, Longitude, Name FROM BP WHERE (Latitude BETWEEN "</span> + brLat + <span style="color:rgb(163,21,21)">" AND "</span> + ulLat + <span style="color:rgb(163,21,21)">") AND (Longitude BETWEEN "</span> + ulLon + <span style="color:rgb(163,21,21)">" AND "</span> + brLon + <span style="color:rgb(163,21,21)">")"
</span> <span style="color:rgb(0,0,255)">Dim</span> myCMD2 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">New</span> SqlCommand(myQuery2, myConn)
<span style="color:rgb(0,0,255)">Dim</span> myReader2 <span style="color:rgb(0,0,255)">As</span> SqlDataReader = myCMD2.ExecuteReader()
<span style="color:rgb(0,0,255)">While</span> myReader2.Read()
myPins = myPins + _
<span style="color:rgb(163,21,21)">"var shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">"=new VEShape(VEShapeType.Pushpin, new VELatLong("</span> + myReader2(0).ToString + <span style="color:rgb(163,21,21)">", "</span> + myReader2(1).ToString + <span style="color:rgb(163,21,21)">"));"</span> + _
<span style="color:rgb(163,21,21)">"shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">".SetCustomIcon('IMG/BP.bmp');"</span> + _
<span style="color:rgb(163,21,21)">"shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">".SetTitle("</span> + <span style="color:rgb(163,21,21)">""""</span> + myReader2(2).ToString + <span style="color:rgb(163,21,21)">""""</span> + <span style="color:rgb(163,21,21)">");"</span> + _
<span style="color:rgb(163,21,21)">"pplBP.AddShape(shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">");"
</span> j = j + 1
<span style="color:rgb(0,0,255)">End</span> <span style="color:rgb(0,0,255)">While
</span> sb.Append(myPins)
myReader2.Close()
<span style="color:rgb(0,0,255)">End</span> <span style="color:rgb(0,0,255)">If
</span> myConn.Close()
<span style="color:rgb(0,0,255)">Case</span> <span style="color:rgb(163,21,21)">"pplRailway"
</span> settings = ConfigurationManager.ConnectionStrings(<span style="color:rgb(163,21,21)">"MyDB"</span>)
<span style="color:rgb(0,0,255)">Dim</span> myConn <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">New</span> SqlConnection(settings.ConnectionString)
<span style="color:rgb(0,0,255)">Dim</span> myQuery1 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = <span style="color:rgb(163,21,21)">"SELECT COUNT(*) FROM Railway WHERE (Latitude BETWEEN "</span> + brLat + <span style="color:rgb(163,21,21)">" AND "</span> + ulLat + <span style="color:rgb(163,21,21)">") AND (Longitude BETWEEN "</span> + ulLon + <span style="color:rgb(163,21,21)">" AND "</span> + brLon + <span style="color:rgb(163,21,21)">")"
</span> <span style="color:rgb(0,0,255)">Dim</span> myCMD1 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">New</span> SqlCommand(myQuery1, myConn)
myConn.Open()
<span style="color:rgb(0,0,255)">Dim</span> myReader1 <span style="color:rgb(0,0,255)">As</span> SqlDataReader = myCMD1.ExecuteReader()
myReader1.Read()
<span style="color:rgb(0,0,255)">If</span> myReader1(0) > 300 <span style="color:rgb(0,0,255)">Then
</span> myPins = myPins + _
<span style="color:rgb(163,21,21)">"map.ShowMessage('There are more than 300s POI of type Railway in this MapView. The Layer will not be shown.');"
</span> sb.Append(myPins)
myReader1.Close()
<span style="color:rgb(0,0,255)">Else
</span> poiCounter = poiCounter + myReader1(0)
myReader1.Close()
<span style="color:rgb(0,0,255)">Dim</span> j <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">Integer</span> = 0
<span style="color:rgb(0,0,255)">Dim</span> myQuery2 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">String</span> = <span style="color:rgb(163,21,21)">"SELECT Latitude, Longitude, Name FROM Railway WHERE (Latitude BETWEEN "</span> + brLat + <span style="color:rgb(163,21,21)">" AND "</span> + ulLat + <span style="color:rgb(163,21,21)">") AND (Longitude BETWEEN "</span> + ulLon + <span style="color:rgb(163,21,21)">" AND "</span> + brLon + <span style="color:rgb(163,21,21)">")"
</span> <span style="color:rgb(0,0,255)">Dim</span> myCMD2 <span style="color:rgb(0,0,255)">As</span> <span style="color:rgb(0,0,255)">New</span> SqlCommand(myQuery2, myConn)
<span style="color:rgb(0,0,255)">Dim</span> myReader2 <span style="color:rgb(0,0,255)">As</span> SqlDataReader = myCMD2.ExecuteReader()
<span style="color:rgb(0,0,255)">While</span> myReader2.Read()
myPins = myPins + _
<span style="color:rgb(163,21,21)">"var shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">"=new VEShape(VEShapeType.Pushpin, new VELatLong("</span> + myReader2(0).ToString + <span style="color:rgb(163,21,21)">", "</span> + myReader2(1).ToString + <span style="color:rgb(163,21,21)">"));"</span> + _
<span style="color:rgb(163,21,21)">"shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">".SetCustomIcon('IMG/Railway.bmp');"</span> + _
<span style="color:rgb(163,21,21)">"shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">".SetTitle("</span> + <span style="color:rgb(163,21,21)">""""</span> + myReader2(2).ToString + <span style="color:rgb(163,21,21)">""""</span> + <span style="color:rgb(163,21,21)">");"</span> + _
<span style="color:rgb(163,21,21)">"pplRailway.AddShape(shape"</span> + j.ToString + <span style="color:rgb(163,21,21)">");"
</span> j = j + 1
<span style="color:rgb(0,0,255)">End</span> <span style="color:rgb(0,0,255)">While
</span> sb.Append(myPins)
myReader2.Close()
<span style="color:rgb(0,0,255)">End</span> <span style="color:rgb(0,0,255)">If
</span> myConn.Close()
<span style="color:rgb(0,0,255)">End</span> <span style="color:rgb(0,0,255)">Select
</span><span style="color:rgb(0,0,255)">Next
</span><span style="color:rgb(0,0,255)">If</span> poiCounter > 300 <span style="color:rgb(0,0,255)">Then
</span> context.Response.Write(<span style="color:rgb(163,21,21)">"map.ShowMessage('The POIs in all layers add up to more than 300. Please deselect a layer or zoom-in.');"</span>)
<span style="color:rgb(0,0,255)">Else
</span> context.Response.Write(sb.ToString())
<span style="color:rgb(0,0,255)">End</span> <span style="color:rgb(0,0,255)">If</span></pre><a href="http://11011.net/software/vspaste"></a>
<p>All right, that's it let's see what we have:
<p><a href="http://blufiles.storage.msn.com/y1pLfDzppuxasiciUZid3mSWNPU-zf-2_jrz21ZYYiaTUHl4_h4r_x98ua777iwecfzFKiUdPdSd3Q"><img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px" alt=14-small src="http://blufiles.storage.msn.com/y1pLfDzppuxashpLb4j48_NVtCbJWMl7NaFGWJ6BjVn6HW2wmW LHCxQY0pNX1uud30WwpYyi67dKlk" border=0></a>
<p>You will find the sample application <a href="http://mappointemea.members.winisp.net/Database/Default.aspx">here</a> and as always the complete source code is available for download from this page as well.
<div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px">Technorati Tags: <a href="http://technorati.com/tags/Virtual Earth" rel=tag>Virtual Earth</a>, <a href="http://technorati.com/tags/AJAX" rel=tag>AJAX</a>, <a href="http://technorati.com/tags/Database" rel=tag>Database</a></div><img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=4819404664324524694&page=RSS%3a+How+to+bring+your+own+content+to+Virtu al+Earth+(Part+4)&referrer=" width="1px" height="1px" border="0" alt=""><img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&NA=1149&PI=88469&RF=&DI=3919&PS=85545&TP=johanneskebeck.spaces.live.com>1=JohannesKebeck">
Click here to view the article. (http://JohannesKebeck.spaces.live.com/Blog/cns!42E1F70205EC8A96!1822.entry)