首先需要了解下Bing Maps Silverlight Control的地图投影模式(MapMode)的架构模型,所有的地图投影模式都是根据投影抽象基类(MapMode)扩展而来。比如二维平面地图投影模式(FlatMapMode)、三维立体地图投影模式(MapMode3D:此投影模式目前尚未使用,为以后的扩展而保留)以及空地图投影模式(NullMode)等。如下图:
如上图所示,其中的墨卡托投影模式(MercatorMode),通过继承于平面地图投影模式(FlatMapMode)对下提供基于墨卡托投影的地图空间映射模型,其下分别实现了加载卫星地图的卫星投影模式(AerialMode)和街道地图的街道投影模式(RoadMode),分别用于实现加载微软卫星地图和街道地图。
如本篇前面提到的实现地图的访问范围和深度缩放级别限制,从上面对Bing Maps Silverlight Control的地图投影模式架构设计的整体分析,可知要实现访问限制可以从MercatorMode基类开始,MercatorMode提供了基于墨卡托投影的地理空间坐标系的完整地图投影模式实现,要自定义的平面地图投影模式则可以直接通过扩展MercatorMode来实现。比如下自定义模式用于加载中国地区的地图瓦片:
/// <summary>
/// 自定义地图投影模式
/// </summary>
public class ChinaMode : MercatorMode
{
}
通过MercatorMode继承过来有分别处理地图加载范围(ConstrainView)和地图深度缩放级别(GetZoomRange)的两个方法。实际上我们要在地图访问上做一些范围的限制主要就是通过重写这两个方法的具体实现。如下代码块演示了加载经度从70--140范围的地图,且地图缩放级别只能是在3--10级之间进行缩放。
/// <summary>
/// 自定义地图投影模式
/// </summary>
public class ChinaMode : MercatorMode
{
/// <summary>
/// 纬度范围
/// </summary>
public Range<double> LatitudeRange = new Range<double>(-50.0, 50.0);
/// <summary>
/// 经度范围(70-140刚好就是中国地图区域)
/// </summary>
public Range<double> LongitudeRange = new Range<double>(70.0, 140.0);
/// <summary>
/// 深度缩放范围(3-10级)
/// </summary>
public Range<double> MapZoomRange = new Range<double>(3.0, 10.0);
/// <summary>
///
/// </summary>
/// <param name="center">地图中心地理坐标</param>
/// <param name="zoomLevel">地图缩放级别</param>
/// <param name="heading">定向视图标题</param>
/// <param name="pitch"></param>
/// <returns>是否有值更改</returns>
public override bool ConstrainView(Location center, ref double zoomLevel, ref double heading, ref double pitch)
{
return base.ConstrainView(center, ref zoomLevel, ref heading, ref pitch);
}
/// <summary>
/// 确定地图深度缩放范围
/// </summary>
/// <param name="center"></param>
/// <returns></returns>
protected override Range<double> GetZoomRange(Location center)
{
return this .MapZoomRange;
}
/// <summary>
/// 重写鼠标中键滚轮操作行为
/// </summary>
/// <param name="e"></param>
public override void OnMouseWheel(MapMouseWheelEventArgs e)
{
if ((e.WheelDelta > 0.0 ) && ( this .ZoomLevel >= this .MapZoomRange.To))
{
e.Handled = true ;
}
else
{
base .OnMouseWheel(e);
}
}
/// <summary>
/// 重写鼠标拖放地图行为
/// </summary>
/// <param name="e"></param>
public override void OnMouseDragBox(MapMouseDragEventArgs e)
{
if ((( this .TargetBoundingRectangle.East <= this .LongitudeRange.To)
&& ( this .TargetBoundingRectangle.West >= this .LongitudeRange.From)))
{
e.Handled = true ;
}
else
{
e.Handled = false ;
}
}
}
通过以上方式自定义的地图投影模式,使用和内置的投影模式一样的简单,可以直接在XAML代码里配置,也可以在后台代码里动态指定。详细如下代码片段:
<m:Map x:Name="map" Margin="0,0,0,0" CredentialsProvider="{StaticResource MyCredentials}"
MouseClick="map_MouseClick"
ScaleVisibility="Visible"
CopyrightVisibility="Collapsed">
<m:Map.Mode>
<!--使用自定义的地图投影模式-->
<mode:ChinaMode></mode:ChinaMode>
</m:Map.Mode>
</m:Map>
后台代码中动态指定和Bing Maps Silverlight Control中内置的投影模式使用方式是完全一样的,直接将投影模式的实例赋值给Map控件的Mode属性。
public MainPage()
{
InitializeComponent();
this.Loaded += (o, e) =>
{
this.map.Mode = new ChinaMode();
map.ZoomLevel=5;
};
}