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”: <pre class="csharpcode">public class DraggablePushpin : Microsoft.Maps.MapControl.Pushpin { private bool isDragging = false; EventHandler ParentMapMousePanHandler; MouseButtonEventHandler ParentMapMouseLeftButtonUpHandler; MouseEventHandler ParentMapMouseMoveHandler;

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

    <span class="rem">// Enable Dragging</span>
    <span class="kwrd">this</span>.isDragging = <span class="kwrd">true</span>;

    <span class="kwrd">base</span>.OnMouseLeftButtonDown(e);
}

<span class="preproc">#region</span> <span class="str">"Mouse Event Handler Methods"</span>

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

<span class="kwrd">void</span> ParentMap_MouseLeftButtonUp(<span class="kwrd">object</span> sender, MouseButtonEventArgs e)
{
    <span class="rem">// Left Mouse Button released, stop dragging the Pushpin</span>
    <span class="kwrd">this</span>.isDragging = <span class="kwrd">false</span>;
}

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

<span class="preproc">#endregion</span> }</pre>