Bing Maps Silverlight CTP: Using MouseClick Event To Add 'Pushpins'

Mar 25, 2009  • Mapping  • Silverlight

In previous tutorials I covered the “Basics of Adding Polygons and Polylines” and “Adding Media (Images, Video, etc.)”, but what about handling user input via Map Events? Well, in this tutorial I’ll cover the basics of working with the Map.MouseClick Event (equivalent of the old “onclick” event in the Virtual Earth JavaScript Control).
This was written for the Bing Maps Silverlight CTP Release. ## Adding a MouseClick Event Handler
In order to wire things up to manipulate the Map using the MouseClick event, we must first attach an Event Handler to it. The Event Handler for the MouseClick event needs to be just like any other event handler in .NET; it must accept two parameters: 1) a “sender” object, and 2) an “EventArgs” object.
Before we create our event handler, it’s worth noting that to be more specific, the value that gets passed to the “EventArgs” parameter of the Map.MouseClick event is actually of Type MapMouseEventArgs.
The MapMouseEventArgs object has the following two properties: <ol> <li>Handled – Gets or Sets a value indicating whether the Map event was handled. If you want to prevent the “default” event handling behavior from executing, then all you need to do is set this to True. </li> <li>ViewportPoint – Gets the viewport point where the mouse event occurred. This is a System.Windows.Point object that represents the X and Y coordinates where the mouse was clicked. </li> </ol>
To declare the MouseClick event handler a method that matched the following signature: void(object sender, MapMouseEventArgs e)
Here’s an example Map.MouseClick event handler method: <pre class="csharpcode">private void myMap_MouseClick(object sender, MapMouseEventArgs e) { }</pre>

You can attach the above event handler from within code:

myMap.MouseClick += new EventHandler(myMap_MouseClick);</pre>


Or, from within XAML:

<m:Map Name="myMap" MouseClick="myMap_MouseClick"></m:Map>
##   ## Get the Location (Lat/Long Coordinate) the Mouse was Clicked One thing that you may have noticed is the MapMouseEventArgs object that is passed to the MouseClick event handler doesn’t contain a “Location” or “LatLong” property of any kind. It’s seems odd at first that there’s no direct way of obtaining the Map Location (Lat/Long) of where the mouse was clicked, but with the help of a little helper method on the Map object itself we can pass in the ViewportPoint (X and Y Coordinates) value contained within the MapMouseEventArgs.ViewportPoint property and get back a Location object with Latitude/Longitude. To obtain the Location (Lat/Long) where the mouse was clicked, simply invoke the Map.ViewportPointToLocation method by passing in the MapMouseEventArgs.ViewportPoint value. The following line of code demonstrates how this can be done within the MouseClick Event Handler we defined above:
var location = clickedMap.ViewportPointToLocation(e.ViewportPoint);
Now that we have the  Location of where the mouse was clicked, we can directly access the Latitude and Longitude values.
var lat = location.Latitude;
var lng = location.Longitude;
##   ## Add a “Pushpin” at the Clicked Location Now that we have a MouseClick Event Handler in place, and we have access to the Location (Latitude/Longitude) where the mouse was clicked; we can go ahead and add a “Pushpin” to the Map at that Location. If you have any questions on how to add a Shape or “Pushpin” to the Map, I recommend reading the following two tutorials: In this example to keep things simple, we’ll add a Square (via the System.Windows.Shapes.Rectangle object) to the Map at the clicked location that is 10x10 in size. Here’s a full code example of the MouseClick event handler we created above, including code that gets the Location clicked and adds the Rectangle Shape to the Map within a new MapLayer:
private void myMap_MouseClick(object sender, MapMouseEventArgs e)
{
    // Set a variable equal to the Map that raised the event
    Map clickedMap = (Map)sender;
    
    // Convert the X/Y Coordinate that was Clicked to a Lat/Long Location
    var location = clickedMap.ViewportPointToLocation(e.ViewportPoint);

    // Create new MapLayer
    var myLayer = new MapLayer();

    // Create a Rectangle Shape to Show as the "Pushpin"
    var rectangle = new System.Windows.Shapes.Rectangle();
    // Set it's Size to 10x10
    rectangle.Width = 10;
    rectangle.Height = 10;
    // Color the Rectangle Red
    rectangle.Fill = new SolidColorBrush(Colors.Red);

    // Center the Rectangle around the location
    PositionMethod position = PositionMethod.Center;

    // Add Rectangle to MapLayer
    myLayer.AddChild(rectangle, location, position);

    // Add the MapLayer to the Map so the "Pushpin" gets displayed
    clickedMap.AddChild(myLayer);
}
One thing that you may want to do when implementing the above example is create only 1 MapLayer and add all the new “Pushpins” to that single MapLayer. This will help improve performance on the Map if you are adding MANY pushpins. For the simple example above this just wasn’t absolutely necessary. ## Auto Expand “Pushpins” using ScaleTransform The best part of the new Virtual Earth Silverlight Map Control is the fact that we can now leverage the full power of Silverlight within our mapping applications/implementations. One of the cool things that can be done are implementing Animations to spice up the user interface. Here’s an example that takes the above MouseClick event handler code that adds a Rectangle “Pushpin” to the Map when the user clicks the Map, and adds a ScaleTransform to “Expand” the Rectangle when the user moves the mouse over it. This is done by setting a ScaleTransform to the Rectangle.RenderTransform during the MouseEnter event, and then removing it during the MouseLeave event. The end result are Rectangle “Pushpins” that Expand when the user Moves the mouse over them. Here’s the full code for Map.MouseClick, Rectangle.MouseEnter and Rectangle.MouseLeave Event Handlers for this “Expand” Animation example:
// Single MapLayer that will contain all "Pushpins"
private MapLayer myLayer = null;

private void myMap_MouseClick(object sender, MapMouseEventArgs e)
{
    // Set a variable equal to the Map that raised the event
    Map clickedMap = (Map)sender;

    // Convert the X/Y Coordinate that was Clicked to a Lat/Long Location
    var location = clickedMap.ViewportPointToLocation(e.ViewportPoint);

    // Check if MapLayer has already been created
    if (myLayer == null)
    {
        // Create new MapLayer
        myLayer = new MapLayer();

        // Add the MapLayer to the Map so the "Pushpin" gets displayed
        clickedMap.AddChild(myLayer);
    }

    // Create a Rectangle Shape to Show as the "Pushpin"
    var rectangle = new System.Windows.Shapes.Rectangle();
    // Set it's Size to 10x10
    rectangle.Width = 10;
    rectangle.Height = 10;
    // Color the Rectangle Red
    rectangle.Fill = new SolidColorBrush(Colors.Red);

    // Attach MouseEnter and MouseLeave Event Handler to the Rectangle
    // This will be used to "Expand" the Rectangle when the user hovers the mouse over it
    rectangle.MouseEnter += new MouseEventHandler(rectangle_MouseEnter);
    rectangle.MouseLeave += new MouseEventHandler(rectangle_MouseLeave);

    // Center the Rectangle around the location
    PositionMethod position = PositionMethod.Center;

    // Add Rectangle to MapLayer
    myLayer.AddChild(rectangle, location, position);
}

void rectangle_MouseEnter(object sender, MouseEventArgs e)
{
    // Get the Rectangle
    var rectangle = (Rectangle)sender;

    // Create new ScaleTransform
    var scaleTransform = new ScaleTransform();

    // Set the Transform to "Expand" the Rectangle
    // equally horizontally and vertically
    scaleTransform.ScaleX = 2.0;
    scaleTransform.ScaleY = 2.0;

    // Set the Scale Center to the Center of the Rectangle
    // This is so it doesn't move when "Expanded"
    scaleTransform.CenterX = rectangle.Width / 2;
    scaleTransform.CenterY = rectangle.Height / 2;

    // Apply the ScaleTransform to the Rectangle
    rectangle.RenderTransform = scaleTransform;
}

void rectangle_MouseLeave(object sender, MouseEventArgs e)
{
    // Get the Rectangle
    var rectangle = (Rectangle)sender;

    // Remove the ScaleTransform
    rectangle.RenderTransform = null;
}
The above code example also includes a modification from the previous examples in this tutorial; it adds all the new Rectangle “Pushpins” to a Single MapLayer instead of adding a new MapLayer for each Rectangle “Pushpin”. ## Conclusion The Map.MouseClick event is really simple to take advantage of, and it’s actually just as easy to add a “Pushpin” during the “onclick” event with the Virtual Earth Silverlight Map Control as it is with the Virtual Earth JavaScript Control. There are a few other events that the Map object exposes, and I’ll be covering some of those in additional tutorials. So, keep an eye out for future posts. ### Previous Tutorial/Article: Overlay OpenStreetMap, OpenAerialMap and Yahoo Map Imagery using Custom Tile Layers