Custom Pushpins in Bing Maps Silverlight

In the Bing Maps Silverlight control there is a Pushpin object that you can use to mark locations on the map. Unfortunately there is little you can do as far as customizations. Changing the icon image is nearly impossible. But not all is lost, Microsoft made it so that we can add UIElements to the map. This gives us the ability to add any kind of UIElement to the map as a pushpin if we wanted. For those who are migrating from the AJAX version of Bing Maps there is a gap in how pushpins are created. In this blog post I’ll explain how I’ve gone about creating a set of tools that gives you the ability to create custom pushpins in a similar manner as it was done in the AJAX control.

In the AJAX control we had the VECustomIconSpecification class for creating custom pushpins. We can create a similar CustomIconSpecific class that consists of a subset of the properties that are in the VECustomIconSpecification. In the following code you may notice that you can specify an Uri or an UIElement. This allows you to create a custom pushpin by either specifying an Uri to an image or to create a UIElement. Specifying an Uri is similar to using the VECustomIconSpecification.Image property, where as using an UIElement is like using the VECustomIconSpecification.CustomHTML property.

CustomIconSpecification.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace BingCustomPushpins
{
    public class CustomIconSpecification
    {
        #region Private Variables

        //Default properties
        private double width = 30;
        private double height = 30;
        private Brush textColor = new SolidColorBrush(Colors.White);
        private double fontSize = 10;
        private Point iconOffset = new Point(0, 0);
        private Point textOffset = new Point(0, 0);

        #endregion

        #region Public Properties

        /// <summary>
        /// A user can use a UIElement as a pushpin icon
        /// </summary>
        public UIElement Icon { get; set; }

        /// <summary>
        /// If a uri is specified for an icon and image will be created. This is only used if the Icon property is null.
        /// </summary>
        public Uri IconUri { get; set; }

        /// <summary>
        /// Offset used for positioning icon so that pin point is anchored to coordinate
        /// </summary>
        public Point IconOffset
        {
            get
            {
                return iconOffset;
            }
            set
            {
                iconOffset = value;
            }
        }

        /// <summary>
        /// Height of the pushpin. This is used for positioning Text and for sizing the icon image
        /// </summary>
        public double Height
        {
            get
            {
                return height;
            }
            set
            {
                height = value;
            }
        }

        /// <summary>
        /// Width of the pushpin. This is used for positioning Text and for sizing the icon image
        /// </summary>
        public double Width
        {
            get
            {
                return width;
            }
            set
            {
                width = value;
            }
        }

        /// <summary>
        /// Custom text to be displayed above the pushpin.
        /// </summary>
        public string TextContent { get; set; }

        /// <summary>
        /// Color of the custom Text
        /// </summary>
        public Brush TextColor
        {
            get
            {
                return textColor;
            }
            set
            {
                textColor = value;
            }
        }

        /// <summary>
        /// Size of the custom Text
        /// </summary>
        public double FontSize
        {
            get
            {
                return fontSize;
            }
            set
            {
                fontSize = value;
            }
        }

        /// <summary>
        /// Offset used for positioning Text so that it is centered over the right part of the pushpin
        /// </summary>
        public Point TextOffet
        {
            get
            {
                return textOffset;
            }
            set
            {
                textOffset = value;
            }
        }

        #endregion
    }
}

 

We can then create a UserControl that uses this CusomtIconSpecification class to generate a UIElement that we can use as a pushpin. We will call this class CustomPushpin. The xaml will be pretty basic and will contain a single Grid object which we will use to add our pushpin icon and custom text too.

CustomPushpin.xaml

<UserControl x:Class="BingCustomPushpins.CustomPushpin"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid Name="PushpinBase"/>
</UserControl>

 

For the code behind to this UserControl we will create three public properties; IconSpecification, location, and MetaData. The IconSpecification will be used to create the pushpin. When this property is set the pushpin content is created. If a UIElement is specified in the specification it will be used as the Icon, otherwise an image will be created from the IconUri if one is specified. Note that a PushpinTools class is used to generate the Image from the IconUri. We will look into this later. If TextContent is specified in the specification a TextBlock is generated and added on top of the pushpin Icon. The Location property is used to specify where this pushpin is to be placed. The MetaData property allows you to store any information that is relevant to this location. This is useful if you want to store a location ID so that you can retrieve details about this location.

CustomPushpin.xaml.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Maps.MapControl;

namespace BingCustomPushpins
{
    public partial class CustomPushpin : UserControl
    {
        #region Private Properties

        private CustomIconSpecification _iconSpec;

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor for CustomPushpin class
        /// </summary>
        public CustomPushpin()
        {
            InitializeComponent();
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Specification to create the custom pushpin
        /// </summary>
        public CustomIconSpecification IconSpecification
        {
            get
            {
                return _iconSpec;
            }
            set
            {
                _iconSpec = value;

                PushpinBase.Children.Clear();

                if (value.Icon != null)
                {
                    PushpinBase.Children.Add(value.Icon);
                }
                else if (value.IconUri != null)
                {
                    PushpinBase.Children.Add(PushpinTools.CreateImagePushpin(value.IconUri, value.Width, value.Height, value.IconOffset));
                }

                if (!string.IsNullOrEmpty(value.TextContent))
                {
                    TextBlock text = new TextBlock();
                    text.Text = value.TextContent;
                    text.TextAlignment = TextAlignment.Center;
                    text.HorizontalAlignment = HorizontalAlignment.Center;
                    text.VerticalAlignment = VerticalAlignment.Center;
                    text.Foreground = value.TextColor;
                    text.FontSize = value.FontSize;
                    text.Margin = new Thickness(value.TextOffet.X, value.TextOffet.Y, 0, 0);
                    PushpinBase.Children.Add(text);
                }
            }
        }

        /// <summary>
        /// The Location in which to display the pushpin
        /// </summary>
        public Location Location { get; set; }

        /// <summary>
        /// Optional metadata that can be used to store data for a pushpin
        /// </summary>
        public object MetaData { get; set; }

        #endregion
    }
}

The following PushpinTools class gives you two useful methods for generating common pushpin UIElements; image pushpins, and circle pushpins.

PushpinTools.cs

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace BingCustomPushpins
{
    public static class PushpinTools
    {
        /// <summary>
        /// Creates an Image pushpin
        /// </summary>
        /// <param name="imageUri">Uri of the image to use for the pushpin icon</param>
        /// <param name="width">Width of the pushpin</param>
        /// <param name="height">Height of the pushpin</param>
        /// <param name="offset">Offset distance for the pushpin so that the point of the
        /// pin is aligned with the associated coordinate.</param>
        /// <returns></returns>
        public static UIElement CreateImagePushpin(Uri imageUri, double width, double height, Point offset)
        {
            return new Image()
            {
                Source = new BitmapImage(imageUri),
                Width = width,
                Height = height,
                Margin = new Thickness(offset.X, offset.Y, 0, 0)
            };
        }

        /// <summary>
        /// Creates a Circle UIElement
        /// </summary>
        /// <param name="radius">Radius of the circle to create</param>
        /// <param name="fillColor">The fill color of the circle</param>
        /// <param name="strokeColor">The stroke color of the circle.
        /// This is used to create a border around the circle</param>
        /// <returns></returns>
        public static UIElement CreateCirclePushpin(double radius, Brush fillColor, Brush strokeColor)
        {
            return new Ellipse()
            {
                Width = radius + radius,
                Height = radius + radius,
                Fill = fillColor,
                Stroke = strokeColor,
                StrokeThickness = 2,
                Margin = new Thickness(-radius, -radius, 0, 0)
            };
        }
    }
}

As a final step it would be useful if we had an easy way to add these custom pushpins to a map layer. We can create a simple extension to the MapLayer class to do this.

BingMapsExtensions.cs

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Maps.MapControl;

namespace BingCustomPushpins
{
    public static class BingMapsExtensions
    {
        /// <summary>
        /// Allows a custom pushpin to be added to a MapLayer
        /// </summary>
        /// <param name="layer">MapLayer to add custom pushpin to</param>
        /// <param name="pushpin">Custom Pushpin to add to layer</param>
        public static void AddChild(this MapLayer layer, CustomPushpin pushpin)
        {
            layer.AddChild(pushpin, pushpin.Location);
        }
    }
}

I’ve put these classes together into a reusable class library so that you can easily add this functionality to your applications. In order to use this class simply add a reference to the dll or project. I’ve put together a sample application that shows how you can use these tools. You can download the complete code with samples here: http://cid-e7dba9a4bfd458c5.skydrive.live.com/self.aspx/VE%20Sample%20code/CustomPushpins.zip

Here is a screen shot of the sample application with two different types of pushpins.

image

Advertisements

4 thoughts on “Custom Pushpins in Bing Maps Silverlight

  1. Thank you very much for this complete solution. I needed the example to help me get a custom configurable pushpin going.

    Cheers!

    • The ideas was to create a class similar to the Custom Pushpins in Bing Maps V6.3 as that’s what developers are used to. This made it more familar for people who are already Bing Maps developers.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s