学习使用Bing Maps Silverlight Control(五):离线使用和自定义地图模式
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。)
输了你,赢了世界又如何...
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!