When building a Bing Maps application, you may want to give the user the ability to drag a pushpin. In the JavaScript version of Bing Maps this can be done by setting the draggable property of a pushpin to true, but the Pushpin class in the .NET version does not have this property, so what can you do?
In this blog post, I’ll show you how to create a reusable user control that gives you draggable pushpins, plus a lot more flexibility in terms of customization.
Some common uses for draggable pushpins include:
Next, add a reference to the Bing Maps SDK. Right click on the References folder and press Add Reference. Select Windows -> Extensions, and then select Bing Maps for C#, C++ and Visual Basic. If you do not see this option, be sure to verify that you have installed the Bing Maps SDK for Windows Store apps. While you are here, also add a reference to the Microsoft Visual C++ Runtime Package, as this is required by the Bing Maps SDK when developing using C# or Visual Basic. Press OK.
In Solution Explorer, set the Active solution platform in Visual Studio by right clicking on the Solution folder and selecting Properties. Select Configuration Properties -> Configuration. Find your project and under the Platform column, set the target platform to x86, and press OK.
Right click on the solution folder and selectAdd -> New Item. Select theUser Controltemplate and give it a name, such as “.” Open thefile and update the XAML to the following:
Now open DraggablePin.xaml.cs or DraggablePin.xaml.vb.
The code-behind for this user control will need a reference to the map control in its constructor and a local reference to it stored in a private variable. This control will use a number of events on the map to enable the dragging functionality.
Next, override the OnPointerPressed event handler to add the required map events for dragging the user control. When the user control is initially pressed, the coordinate of the center of the map will be stored. Next, fill in the ViewChange event of the map to set the center of the map to the stored center value, which will keep the map from panning when dragging the user control.
Set the PointerMovedOverride event of the map to update the position of the user control as it is dragged. Then set the OnPointerReleasedOverride event of the map to release all the events from the map that were used for dragging the user control.
Now add a Boolean property called Draggable, which can be used to disable the dragging functionality of the pushpin. Lastly, expose three Action events: DragStart, Drag, and DragEnd, for use in future applications.
The following example shows the complete code for the user control.
Now that you have a DraggablePin user control, you can now try using it in an app. Open MainPage.xaml and update the XAML to the following:
Open MainPage.xaml.cs or MainPage.xaml.vb.
In the constructor, add a handler to the MapLoaded event of the map. Set the handler to create a DraggablePin and add it to the center of the map. Then attach to the Drag event of the pin and have it update the coordinates displayed in a TextBlock at the bottom of the map, as shown in the following example.
Now if you run the application you will see a blue circle pushpin in the center of the map. Simply press down on it and drag it around on the screen using a mouse or your finger if you have a touch screen device.
You can find the complete source code for this blog post in the MSDN Code Sample Gallery. If you are working with the WPF version of the control, I have a similar code sample available here.
- Ricky Brundritt, EMEA Bing Maps TSP
DraggablePushpins-Thumbnail.pngIn this blog post, I’ll show you how to create a reusable user control that gives you draggable pushpins, plus a lot more flexibility in terms of customization.
Some common uses for draggable pushpins include:
-
Allowing the user to edit locations on the map by moving pushpins.
-
Using draggable pushpins as handles for data points in drawing tools.
Creating the user control
To get started, open Visual Studio and create a new project in C# or Visual Basic. Select the Blank App (XAML) template, name the application and then press OK.Next, add a reference to the Bing Maps SDK. Right click on the References folder and press Add Reference. Select Windows -> Extensions, and then select Bing Maps for C#, C++ and Visual Basic. If you do not see this option, be sure to verify that you have installed the Bing Maps SDK for Windows Store apps. While you are here, also add a reference to the Microsoft Visual C++ Runtime Package, as this is required by the Bing Maps SDK when developing using C# or Visual Basic. Press OK.
In Solution Explorer, set the Active solution platform in Visual Studio by right clicking on the Solution folder and selecting Properties. Select Configuration Properties -> Configuration. Find your project and under the Platform column, set the target platform to x86, and press OK.
Right click on the solution folder and selectAdd -> New Item. Select theUser Controltemplate and give it a name, such as “.” Open thefile and update the XAML to the following:
<UserControl x:Class="DraggablePushpin.DraggablePin" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:DraggablePushpin" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"> <Ellipse Height="30" Width="30" Fill="Blue" Stroke="White" StrokeThickness="5" Margin="-15,-15,0,0"/> </UserControl> |
Now open DraggablePin.xaml.cs or DraggablePin.xaml.vb.
The code-behind for this user control will need a reference to the map control in its constructor and a local reference to it stored in a private variable. This control will use a number of events on the map to enable the dragging functionality.
Next, override the OnPointerPressed event handler to add the required map events for dragging the user control. When the user control is initially pressed, the coordinate of the center of the map will be stored. Next, fill in the ViewChange event of the map to set the center of the map to the stored center value, which will keep the map from panning when dragging the user control.
Set the PointerMovedOverride event of the map to update the position of the user control as it is dragged. Then set the OnPointerReleasedOverride event of the map to release all the events from the map that were used for dragging the user control.
Now add a Boolean property called Draggable, which can be used to disable the dragging functionality of the pushpin. Lastly, expose three Action events: DragStart, Drag, and DragEnd, for use in future applications.
The following example shows the complete code for the user control.
C# |
using Bing.Maps; using System; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; namespace DraggablePushpin { publicsealedpartialclassDraggablePin : UserControl { privateMap _map; privatebool isDragging = false; Location _center; public DraggablePin(Map map) { this.InitializeComponent(); _map = map; } ///<summary> /// A boolean indicating whether the pushpin can be dragged. ///</summary> publicbool Draggable { get; set; } ///<summary> /// Occurs when the pushpin is being dragged. ///</summary> publicAction<Location> Drag; ///<summary> /// Occurs when the pushpin starts being dragged. ///</summary> publicAction<Location> DragStart; ///<summary> /// Occurs when the pushpin stops being dragged. ///</summary> publicAction<Location> DragEnd; protectedoverridevoid OnPointerPressed(PointerRoutedEventArgs e) { base.OnPointerPressed(e); if (Draggable) { if (_map != null) { //Store the center of the map _center = _map.Center; //Attach events to the map to track touch and movement events _map.ViewChanged += Map_ViewChanged; _map.PointerReleasedOverride += Map_PointerReleased; _map.PointerMovedOverride += Map_PointerMoved; } var pointerPosition = e.GetCurrentPoint(_map); Location location = null; //Convert the point pixel to a Location coordinate if (_map.TryPixelToLocation(pointerPosition.Position, out location)) { MapLayer.SetPosition(this, location); } if (DragStart != null) { DragStart(location); } //Enable Dragging this.isDragging = true; } } privatevoid Map_PointerMoved(object sender, PointerRoutedEventArgs e) { //Check if the user is currently dragging the Pushpin if (this.isDragging) { //If so, move the Pushpin to where the pointer is. var pointerPosition = e.GetCurrentPoint(_map); Location location = null; //Convert the point pixel to a Location coordinate if (_map.TryPixelToLocation(pointerPosition.Position, out location)) { MapLayer.SetPosition(this, location); } if (Drag != null) { Drag(location); } } } privatevoid Map_PointerReleased(object sender, PointerRoutedEventArgs e) { //Pushpin released, remove dragging events if (_map != null) { _map.ViewChanged -= Map_ViewChanged; _map.PointerReleasedOverride -= Map_PointerReleased; _map.PointerMovedOverride -= Map_PointerMoved; } var pointerPosition = e.GetCurrentPoint(_map); Location location = null; //Convert the point pixel to a Location coordinate if (_map.TryPixelToLocation(pointerPosition.Position, out location)) { MapLayer.SetPosition(this, location); } if (DragEnd != null) { DragEnd(location); } this.isDragging = false; } privatevoid Map_ViewChanged(object sender, ViewChangedEventArgs e) { if (isDragging) { //Reset the map center to the stored center value. //This prevents the map from panning when we drag across it. _map.Center = _center; } } } } |
Visual Basic |
Imports Bing.Maps PublicNotInheritableClassDraggablePin InheritsUserControl Private _map AsMap Private isDragging AsBoolean = False Private _center AsLocation PublicSubNew(map AsMap) Me.InitializeComponent() _map = map EndSub '''<summary> ''' A boolean indicating whether the pushpin can be dragged. '''</summary> PublicProperty Draggable() AsBoolean Get Return m_Draggable EndGet Set(value AsBoolean) m_Draggable = Value EndSet EndProperty Private m_Draggable AsBoolean ''' <summary> ''' Occurs when the pushpin is being dragged. ''' </summary> Public Drag AsAction(OfLocation) ''' <summary> ''' Occurs when the pushpin starts being dragged. ''' </summary> Public DragStart AsAction(OfLocation) ''' <summary> ''' Occurs when the pushpin stops being dragged. ''' </summary> Public DragEnd AsAction(OfLocation) ProtectedOverridesSub OnPointerPressed(e AsPointerRoutedEventArgs) MyBase.OnPointerPressed(e) If Draggable Then If _map IsNotNothingThen ''Store the center of the map _center = _map.Center ''Attach events to the map to track touch and movement events AddHandler _map.ViewChanged, AddressOf Map_ViewChanged AddHandler _map.PointerReleasedOverride, AddressOf Map_PointerReleased AddHandler _map.PointerMovedOverride, AddressOf Map_PointerMoved EndIf Dim pointerPosition = e.GetCurrentPoint(_map) Dim location AsLocation = Nothing ''Convert the point pixel to a Location coordinate If _map.TryPixelToLocation(pointerPosition.Position, location) Then MapLayer.SetPosition(Me, location) EndIf If DragStart IsNotNothingThen DragStart(location) EndIf ''Enable Dragging Me.isDragging = True EndIf EndSub PrivateSub Map_PointerMoved(sender AsObject, e AsPointerRoutedEventArgs) ''Check if the user is currently dragging the Pushpin IfMe.isDraggingThen ''If so, move the Pushpin to where the pointer is. Dim pointerPosition = e.GetCurrentPoint(_map) Dim location AsLocation = Nothing ''Convert the point pixel to a Location coordinate If _map.TryPixelToLocation(pointerPosition.Position, location) Then MapLayer.SetPosition(Me, location) EndIf If Drag IsNotNothingThen Drag(location) EndIf EndIf EndSub PrivateSub Map_PointerReleased(sender AsObject, e AsPointerRoutedEventArgs) ''Pushpin released, remove dragging events If _map IsNotNothingThen RemoveHandler _map.ViewChanged, AddressOf Map_ViewChanged RemoveHandler _map.PointerReleasedOverride, AddressOf Map_PointerReleased RemoveHandler _map.PointerMovedOverride, AddressOf Map_PointerMoved EndIf Dim pointerPosition = e.GetCurrentPoint(_map) Dim location AsLocation = Nothing ''Convert the point pixel to a Location coordinate If _map.TryPixelToLocation(pointerPosition.Position, location) Then MapLayer.SetPosition(Me, location) EndIf If DragEnd IsNotNothingThen DragEnd(location) EndIf Me.isDragging = False EndSub PrivateSub Map_ViewChanged(sender AsObject, e AsViewChangedEventArgs) If isDragging Then ''Reset the map center to the stored center value. ''This prevents the map from panning when we drag across it. _map.Center = _center EndIf EndSub EndClass |
Implementing the user control in an application
Now that you have a DraggablePin user control, you can now try using it in an app. Open MainPage.xaml and update the XAML to the following:<Page x:Class="DraggablePushpin.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:DraggablePushpin" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:m="using:Bing.Maps"> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <m:Map Name="MyMap" Credentials="YOUR_BING_MAPS_KEY"/> <Border Background="Black" HorizontalAlignment="Center" VerticalAlignment="Bottom"> <TextBlock Name="CoordinatesTbx" FontSize="24" Margin="10"/> </Border> </Grid> </Page> |
In the constructor, add a handler to the MapLoaded event of the map. Set the handler to create a DraggablePin and add it to the center of the map. Then attach to the Drag event of the pin and have it update the coordinates displayed in a TextBlock at the bottom of the map, as shown in the following example.
C# |
using Windows.UI.Xaml.Controls; namespace DraggablePushpin { publicsealedpartialclassMainPage : Page { public MainPage() { this.InitializeComponent(); MyMap.Loaded += MyMap_Loaded; } privatevoid MyMap_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e) { DraggablePin pin = newDraggablePin(MyMap); //Set the location of the pin to the center of the map. Bing.Maps.MapLayer.SetPosition(pin, MyMap.Center); //Set the pin as draggable. pin.Draggable = true; //Attach to the drag action of the pin. pin.Drag += Pin_Dragged; //Add the pin to the map. MyMap.Children.Add(pin); } privatevoid Pin_Dragged(Bing.Maps.Location location) { CoordinatesTbx.Text = string.Format("{0:N5},{1:N5}", location.Latitude,location.Longitude); } } } |
Visual Basic |
Imports Windows.UI.Xaml.Controls PublicNotInheritableClassMainPage InheritsPage PublicSubNew() InitializeComponent() AddHandler MyMap.Loaded, AddressOf MyMap_Loaded EndSub PrivateSub MyMap_Loaded(sender AsObject, e As Windows.UI.Xaml.RoutedEventArgs) Dim pin AsNewDraggablePin(MyMap) ''Set the location of the pin to the center of the map. Bing.Maps.MapLayer.SetPosition(pin, MyMap.Center) ''Set the pin as draggable. pin.Draggable = True ''Attach to the drag action of the pin. pin.Drag = AddressOf Pin_Dragged ''Add the pin to the map. MyMap.Children.Add(pin) EndSub PrivateSub Pin_Dragged(location As Bing.Maps.Location) CoordinatesTbx.Text = String.Format("{0:N5},{1:N5}", location.Latitude,location.Longitude) EndSub EndClass |
Now if you run the application you will see a blue circle pushpin in the center of the map. Simply press down on it and drag it around on the screen using a mouse or your finger if you have a touch screen device.
You can find the complete source code for this blog post in the MSDN Code Sample Gallery. If you are working with the WPF version of the control, I have a similar code sample available here.
- Ricky Brundritt, EMEA Bing Maps TSP