Working with Map Modes

This documentation is no longer available on MSDN, however it is available as a CHM download.

This topic describes how to work with the MapMode class to customize user interactions and map tile layers. When you create a new MapMode object, you are creating a 2D projection of the Earth. In the Bing Maps Silverlight Control, there are two main map modes that all other map modes are based on: FlatMapMode and MercatorMode. The FlatMapMode is a flattened representation of the Earth. MercatorMode is derived from FlatMapMode and represents a cylindrical projection of the Earth onto a 2D surface. The Mercator projection shows lines of latitude and longitude as perpendicular straight lines. The two standard map modes available in Bing Maps Silverlight Control are derived from MercatorMode and include RoadMode and AerialMode. Most often you derive from one of these classes so that you have the base tile layer available when defining the behavior of your new map mode. This is demonstrated in the Example section below.

The simplest use of map mode customization is an empty map containing no base tile layer. Creating this empty representation is done by using the MercatorMode constructor. You can also specify your own tile source to overlay onto the map, but that is beyond the scope of this topic. When you instantiate your Map to use the MercatorMode, you can add tile overlays, shapes, images or videos to one or more MapLayer objects as discussed in other topics in the Developing with the Silverlight Map Control section. For example, you can add the following MapPolygon to the empty map.

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

using Microsoft.Maps.MapControl;
using Microsoft.Maps.MapControl.Core;

namespace SilverlightApplication1
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();

            //Change the map mode to the base Mercator mode
            myMap.Mode = new MercatorMode();
            myMap.SetView(new Location(47.606115, -122.324495), 15);

            //Add new MapLayer containing the shape 
            MapLayer newLayer = new MapLayer();
            MapPolygon poly = new MapPolygon();

            //Define the polygon vertices
            LocationCollection boundingLocations = new LocationCollection();
            boundingLocations.Add(new Location(47.605,-122.323));
            boundingLocations.Add(new Location(47.607,-122.323));
            boundingLocations.Add(new Location(47.606115,-122.325));

            //Set the polygon properties
            poly.Locations = boundingLocations;
            poly.Fill = new SolidColorBrush(Colors.Green);
            poly.Stroke = new SolidColorBrush(Colors.Blue);
            poly.StrokeThickness = 4;
            newLayer.Children.Add(poly);

            //Add the layer containing the polygon to the map
            myMap.Children.Add(newLayer);
       }
    }
}

Ee681896.7a117699-3fd7-4118-932c-490cc742ea89(en-us,MSDN.10).jpg

To define how users can interact with your map, you need to override methods and properties in your custom map mode implementation. Functionality that can be overridden includes restricting the map view, defining the zoom range, managing how keyboard and mouse events affect map navigation, and defining how a Location on the map and a Point on the screen correspond. For a full list of MapMode members, see the MapMode topic.

The following examples demonstrates creating a custom map mode based on the AerialMode class. This custom map mode constrains the viewable map and zoom level to the downtown Seattle area. The constrained map does not allow you to zoom or pan beyond the specified range values (validLatitudeRange, validLongitudeRange, and getZoomRange). This example overrides the GetZoomRange method to define the valid zoom range for the current map view. In this case you only want to allow zoom levels 14 to 21 in order to stay within the downtown Seattle area. The ConstrainView method is overridden in order to specify the bounding rectangle in which you are allowed to pan the map. Any attempt to pan the map outside this bounding rectangle sets the center of the map to the nearest boundary.

Ee681896.note(en-us,MSDN.10).gifNote:
GetZoomRange and ConstrainView execute every time the map view changes.

<UserControl x:Class="SilverlightTest1.CustomMapMode"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:m="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl"
    Width="1024" Height="768">
    <Grid x:Name="LayoutRoot" Background="White">
        <m:Map x:Name="MapCustomMode" CredentialsProvider="your key" >
        </m:Map>
    </Grid>
</UserControl>
	
using System.Windows.Controls;
using Microsoft.Maps.MapControl;

namespace SilverlightTest1
{
    public class SeattleMapMode : AerialMode
    {
        private Range<double> validLatitudeRange;
        private Range<double> validLongitudeRange;

        public SeattleMapMode()
        {
            // The latitude value range (From = bottom most latitude, To = top most latitude)
            validLatitudeRange = new Range<double>(47.58346, 47.62877);
            // The longitude value range (From = left most longitude, To = right most longitude)
            validLongitudeRange = new Range<double>(-122.36298, -122.28599);
        }

        // Restricts the map view.
        protected override Range<double> GetZoomRange(Location center)
        {
            // The allowable zoom levels - 14 to 21.
            return new Range<double>(14, 21);
        }

        
        // This method is called when the map view changes on Keyboard 
        // and Navigation Bar events.
        public override bool ConstrainView(Location center, ref double zoomLevel, ref double heading, ref double pitch)
        {
            bool isChanged = base.ConstrainView(center, ref zoomLevel, ref heading, ref pitch);

            double newLatitude = center.Latitude;
            double newLongitude = center.Longitude;

            // If the map view is outside the valid longitude range,
            // move the map back within range.
            if (center.Longitude > validLongitudeRange.To)
            {
                newLongitude = validLongitudeRange.To;
            }
            else if (center.Longitude < validLongitudeRange.From)
            {
                newLongitude = validLongitudeRange.From;
            }

            // If the map view is outside the valid latitude range,
            // move the map back within range.
            if (center.Latitude > validLatitudeRange.To)
            {
                newLatitude = validLatitudeRange.To;
            }
            else if (center.Latitude < validLatitudeRange.From)
            {
                newLatitude = validLatitudeRange.From;
            }

            // The new map view location.
            if (newLatitude != center.Latitude || newLongitude != center.Longitude)
            {
                center.Latitude = newLatitude;
                center.Longitude = newLongitude;
                isChanged = true;
            }

            // The new zoom level.
            Range<double> range = GetZoomRange(center);
            if (zoomLevel > range.To)
            {
                zoomLevel = range.To;
                isChanged = true;
            }
            else if (zoomLevel < range.From)
            {
                zoomLevel = range.From;
                isChanged = true;
            }

            return isChanged;
        }
    }

    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();

            // Sets the map to the custom map mode.
            MapCustomMode.Mode = new SeattleMapMode();
        }
    }
}
	

In the example above, the map navigation control is still available, so the user can still select the Road and Aerial map modes to navigate beyond the bounds that you have defined in the SeattleMapMode class. To prevent this, you can customize the navigation control so that the user cannot access these other modes. Your MainPage class code now looks like the code below.


 public partial class MainPage : UserControl
 {
     public MainPage()
     {
         InitializeComponent();

         // Sets the map to the custom map mode.
         MapCustomMode.Mode = new SeattleMapMode();

         MapCustomMode.MapForeground.TemplateApplied += new EventHandler(MapForeground_TemplateApplied);
         
     }

     void MapForeground_TemplateApplied(object sender, EventArgs e)
     {
         MapCustomMode.MapForeground.NavigationBar.TemplateApplied += new EventHandler(NavigationBar_TemplateApplied);
     }

     void NavigationBar_TemplateApplied(object sender, EventArgs e)
     {
         NavigationBar navControl = MapCustomMode.MapForeground.NavigationBar;

         navControl.HorizontalPanel.Children.Clear();
     }


}
 
Show: