Chris Pietschmann

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

NAVIGATION - SEARCH

Draggable Pushpins using Bing Maps Silverlight Control

Using a map to visualize data within an application is great, but you must first get the location of the data to be displayed. If you have the address you can geocode it using the Bing Maps Web Services, but "What if you can't geocode it?" Or, "What if the geocoding can't find the address?" Well, if your user knows where the location is, then you can have them point it out by clicking on the map. Creating Pushpins in response to a users click is nice, but wouldn't it be even nicer if they could "Click and Drag" the Pushpin around to define/edit/change the location of the data entity?

I have even seen this discussed a bit in regards to the Bing Maps Silverlight Control, and it isn't something that is built into the map control directly. However it isn't too difficult to implement, if you know what to do. So I decided to create and post a simple "DraggablePushpin" object deriving from the "Microsoft.Maps.MapControl.Pushpin" object that implements Dragging in a nice, self contained fashion. There's no need to wire up any events, you simple add a "DraggablePushpin" to you Map, and the user can drag it around.

Here's the code for the "DraggablePushpin":

public class DraggablePushpin : Microsoft.Maps.MapControl.Pushpin
{
    private bool isDragging = false;
    EventHandler<MapMouseDragEventArgs> ParentMapMousePanHandler;
    MouseButtonEventHandler ParentMapMouseLeftButtonUpHandler;
    MouseEventHandler ParentMapMouseMoveHandler;

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        // Check if the Map Event Handlers have been created/attached to the Map
        // If not, then attach them. This is done in the "Pushpin.OnMouseLeftButtonDown"
        // event because we don't know when the Pushpin is added to a Map or MapLayer, but
        // we do konw that when this event is fired the Pushpin will already have been added.
        var parentLayer = this.Parent as MapLayer;
        if (parentLayer != null)
        {
            var parentMap = parentLayer.ParentMap;
            if (parentMap != null)
            {
                if (this.ParentMapMousePanHandler == null)
                {
                    this.ParentMapMousePanHandler = new EventHandler<MapMouseDragEventArgs>(ParentMap_MousePan);
                    parentMap.MousePan += this.ParentMapMousePanHandler;
                }
                if (this.ParentMapMouseLeftButtonUpHandler == null)
                {
                    this.ParentMapMouseLeftButtonUpHandler = new MouseButtonEventHandler(ParentMap_MouseLeftButtonUp);
                    parentMap.MouseLeftButtonUp += this.ParentMapMouseLeftButtonUpHandler;
                }
                if (this.ParentMapMouseMoveHandler == null)
                {
                    this.ParentMapMouseMoveHandler = new MouseEventHandler(ParentMap_MouseMove);
                    parentMap.MouseMove += this.ParentMapMouseMoveHandler;
                }
            }
        }

        // Enable Dragging
        this.isDragging = true;

        base.OnMouseLeftButtonDown(e);
    }

    #region "Mouse Event Handler Methods"

    void ParentMap_MousePan(object sender, MapMouseDragEventArgs e)
    {
        // If the Pushpin is being dragged, specify that the Map's MousePan
        // event is handled. This is to suppress the Panning of the Map that
        // is done when the mouse drags the map.
        if (this.isDragging)
        {
            e.Handled = true;
        }
    }

    void ParentMap_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        // Left Mouse Button released, stop dragging the Pushpin
        this.isDragging = false;
    }

    void ParentMap_MouseMove(object sender, MouseEventArgs e)
    {
        var map = sender as Microsoft.Maps.MapControl.Map;
        // Check if the user is currently dragging the Pushpin
        if (this.isDragging)
        {
            // If so, the Move the Pushpin to where the Mouse is.
            var mouseMapPosition = e.GetPosition(map);
            var mouseGeocode = map.ViewportPointToLocation(mouseMapPosition);
            this.Location = mouseGeocode;
        }
    }

    #endregion
}
blog comments powered by Disqus