6 离线使用
在笔记第一部分的时候就提到如果要使用Bing Maps Silverlight Control 进行开发,需要申请一个key,不让会显示一个错误提示出来。但是在实际开发或使用过程中,使用环境和地图数据可能不是在线的,但控件因为验证失败仍然会显示以下内容:
如何去掉这个提示?最简单的方式就是自己扩展一个Map控件,在其构造方法中将错误提示层给干掉,然后再项目中使用自定义的Map控件,大致可以如下实现:
首先,自定义一个类型,继承自Map类:
namespace CustomBingMaps {public class OfflineMap : Map{public OfflineMap(): base(){base.LoadingError += (sender, e) =>{base.RootLayer.Children.RemoveAt(5);};}} }
然后,在前台引用刚才的自定义类型的命名空间,就可以使用这个扩展的OfflineMap控件了:
<UserControl x:Class="xwgmap_sl_client.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:m="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl"xmlns:c="clr-namespace:CustomBingMaps"mc:Ignorable="d"d:DesignHeight="300" d:DesignWidth="400"><Grid x:Name="LayoutRoot" Background="White"><c:OfflineMap Name="map" LogoVisibility="Collapsed" CopyrightVisibility="Collapsed"></c:OfflineMap></Grid> </UserControl>
这样在离线使用控件的时候就不会再显示错误了。
(以上方法转载自:http://www.cnblogs.com/beniao/archive/2010/05/28/1745896.html,相关原理没有转载,有兴趣的话可以去原博客查看。)
7 自定义显示范围
如果使用自己的地图数据进行加载使用,一般来说相对于全球只会覆盖一部分的地区,剩下的地区都是空白,还有地图数据不一定对应所有的缩放级别都有,如何限制可以查看的地图范围和缩放级别呢?答案就是自定义MapMode。
在这里,自定义MapMode来限制视野范围主要是要重写两个方法:GetZoomRange 和 ConstrainView,前者用来限制缩放范围,后者则将经纬度和缩放进行统一限制。
还有一个问题需要说明,Bing Maps自带的RoadMode(普通地图)和AerialMode(卫星地图)都是继承自MercatorMode(墨卡托投影),所以这里也将直接从MercatorMode派生出自定义MapMode(当然也可以扩展前两个模式)。但是MercatorMode没有任何TileSource,所以如果直接显示出来就什么也看不到了,所以还要再给自定义类型加上Tile图层。
首先是自定义了一个必应地图(简体中文)的TileSource类:
/// <summary> /// 必应地图的Tile系统 /// </summary> public class BingDituTileSource : LocationRectTileSource {public BingDituTileSource(){//设定瓦片源Tile系统的Uri格式,其中的{quadkey}就是每个瓦片quadkey的对应位置//这里使用的是必应地图(简体中文)的Tile系统UriFormat = "http://r0.tiles.ditu.live.com/tiles/r{quadkey}.png?g=99&mkt=zh-cn";} }
下面就开始自定义ChinaMode类,为了方便以后的扩展,这里将对MercatorMode的扩展提取成CustomModeBase,在此基础上再扩展出ChinaMode。所以首先是CustomModeBase的代码:
/// <summary> /// 自定义地图基类,实现了视野范围的限制和自定义瓦片源。 /// 使用前请初始化: /// TileLayer(瓦片源) /// LatitudeRange(经度范围) /// LongitudeRange(纬度范围) /// MapZoomRange(缩放范围) /// </summary> public class CustomModeBase : MercatorMode {/// <summary>/// 用于呈现Tile层/// </summary>public override UIElement Content{get{return this.TileLayer;}}/// <summary>/// 存储Tile图层/// </summary>public MapTileLayer TileLayer;/// <summary>/// 纬度范围/// </summary>public Range<double> LatitudeRange;/// <summary>/// 经度范围/// </summary>public Range<double> LongitudeRange;/// <summary>/// 缩放范围/// </summary>public Range<double> MapZoomRange;/// <summary>/// 初始化基类字段/// </summary>public CustomModeBase(){this.TileLayer = new MapTileLayer();this.LatitudeRange = new Range<double>(-90, 90);this.LongitudeRange = new Range<double>(-180, 180);this.MapZoomRange = new Range<double>(1, 20);}/// <summary>/// 缩放范围/// </summary>/// <param name="center"></param>/// <returns></returns>protected override Range<double> GetZoomRange(Location center){return MapZoomRange;}//当地图视野改变时将调用该函数进行处理(即可达到限制地图范围的效果)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 (center.Longitude > LongitudeRange.To){newLongitude = LongitudeRange.To;}else if (center.Longitude < LongitudeRange.From){newLongitude = LongitudeRange.From;}//如果视野经度超出范围,则将视野范围限制在边界if (center.Latitude > LatitudeRange.To){newLatitude = LatitudeRange.To;}else if (center.Latitude < LatitudeRange.From){newLatitude = LatitudeRange.From;}//设置新的地图视野(限制在范围中)if (newLatitude != center.Latitude || newLongitude != center.Longitude){center.Latitude = newLatitude;center.Longitude = newLongitude;isChanged = true;}//设置新的地图缩放级别(限制在范围中)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;} }
然后再新建ChinaMode类,继承自CustomModeBase:
/// <summary> /// 中国地图模式 /// </summary> public class ChinaMode : CustomModeBase {public ChinaMode(){//初始化必应地图(简体中文)瓦片源BingDituTileSource TileSource = new BingDituTileSource();//向瓦片图层添加瓦片源base.TileLayer.TileSources.Add(TileSource);//向地图添加限制范围base.LatitudeRange = new Range<double>(0, 50);base.LongitudeRange = new Range<double>(70, 140);base.MapZoomRange = new Range<double>(5, 10);} }
需要说明的是:这里经纬度的限制范围并不是边界范围,而是视野中心(Center)的边界,可能是为了方便适应不同的分辨率和缩放级别吧,所以处理经纬度边界的时候需要比较谨慎。缩放的级别就是可以缩放的级别,这个没有问题,缩放级别设定后,界面工具条上的缩放工具栏也会自动的做出相应的改变。
如何使用MapMode就比较简单了,比如在后台代码进行改变:
public MainPage() {InitializeComponent();map.Mode = new ChinaMode(); }
也可以在前台直接设置Mode属性:
<c:OfflineMap Name="map"CopyrightVisibility="Collapsed" LogoVisibility="Collapsed" ScaleVisibility="Collapsed"><c:OfflineMap.Mode><c:ChinaMode></c:ChinaMode></c:OfflineMap.Mode> </c:OfflineMap>
这时可以通过设计视图的预览直接看到效果。
最终效果(各种限制无法在截图中展示,请自行体验。。。):
(以上内容参考自:http://msdn.microsoft.com/en-us/library/ee681896.aspx,更多内容请参阅msdn。)