LBS应用在有一段时间曾经一度风靡整个移动互联网行业,手机相对于PC一个巨大优势之一就是能够通过电信移动网络(如GSM网、CDMA网)或外部定位方式(如GPS)获取移动终端用户的位置信息,而这种应用,往往和地图有不可分割的关系,因此,基于地图的开发,是每一个手机应用开发者必须熟练掌握的技术,因为地图开发知识点较多,本文主要总结一些WP地图开发的重要知识点,下一篇博客再结合本文的知识点进行实例讲解。
一、开发必备
Bing地图是微软自家的地图,也是WP默认的地图,我们就先从Bing地图说起,首先,要使用Bing Map必须创建一个Bing Maps免费账号,程序中需要绑定这个账号(Map控件本身和使用Bing Map Soap服务都需要),注册地址是http://www.bingmapsportal.com,具体如何注册我就不浪费篇幅了,搞不定的朋友网上搜一下资料吧。
创建Windows Phone项目后,添加地图控件的引用,如下图:
然后同工具箱中拖入一个Map控件到MainPage界面,Xmal文件中会加入如下语句:
<my:Map Height="50" HorizontalAlignment="Left" Margin="296,115,0,0" Name="map1" VerticalAlignment="Top" Width="100" />
去掉宽、高、对齐等一些属性,以便地图等填充整个Grid,代码如下:
<my:Map Name="map1"/>
在MainPage的构造函数中,给Map控件绑定上面注册的密钥(不绑定密钥地图中将提示Invalid Credentials),语句如下形式:
this.map1.CredentialsProvider = new ApplicationIdCredentialsProvider("注册的密钥");
此时,运行就可以看到地图界面了。
二、常用属性
下面介绍Map控件的几个重要属性。
1. 设置CopyrightVisibility和LogoVisibility为Collapsed来隐藏版权和Logo,语句如下:
this.map1.LogoVisibility = Visibility.Collapsed; this.map1.CopyrightVisibility = Visibility.Collapsed;
2. 通过Mode属性设置地图模式,Mode为MapMode类型,此类型相关类继承关系如下:
一般常用的就是AerialMode和RoadMode类,因为地图常用模式就是航测图模式和线路图模式,可以通过如下语句来设置
this.map1.Mode = new AerialMode(true);//航测图模式,参数设为true显示地图标签,默认为false this.map1.Mode = new RoadMode();//线路图模式
当然我们也可以以上面某个类作为基类进行扩展,实现满足自己需要的模式。
3. 通过ZoomLevel设置地图的变焦倍数,语句如下:
this.map1.ZoomLevel = 10;
数值是一个double类型,范围没有限制,但是太大或太小实际上就没有意义了,具体的变焦范围主要还是根据自己的需要来定。
4. 通过Center属性设置默认显示的中心,如默认显示北京市中心:
this.map1.Center = new GeoCoordinate(39.9, 116.3);
注:GeoCoordinate类需要添加System.Device引用。
三、组成元素
1. 地图
在WP地图中,图层用Map类来描述,查看Map的基类MapBase,如下图:
能发现,Map类实际上最终继承自我们熟悉的ContentControl基类(silverlight控件中,很多控件都继承自此类,比如Button)。除此以外,Map还有一个属性Children,在silverlight中,往往Panel类才具有该属性,说明Map其实也是个容器。结合现实,我们也不难想象,一张地图必要容纳了很多元素,比如山峰、河流、建筑、道路等等。
2. 图层
一张地图实际上是由若干个图层组成的,比如在一张城市地图中,高速公路,普通道路、名胜古迹一般用3个不同的图层来表示,关于GIS方面的知识,大家可以查阅相关资料。
在WP地图中,图层用MapLayer类来描述,查看MapLayer类,发现其间接继承自Panel,如下图:
这说明图层实际上也是个容器,Children属性必然是图层的常用属性之一。
关于图层,还有一个非常常用的类MapTileLayer,运行地图运用,如果大家网速不是很快,能够感觉的到,一张地图实际上是一块块加载出来的,从MapTileLayer这个类名我们能看到一个敏感的词Tile,和游戏开发中地图加载一样,实际上一张地图就是由若干Tile拼接而成的。MapLayer和MapTileLayer除了都代表一个图层外,并无什么特别的联系,各自用途不同。MapLayer就是个容器,而MapTileLayer通过TileSources属性加载多个Tile来呈现一个图层。两者可以同时作为Map的Children存在。
此外,有必要提一下MapItemsControl这个控件,实际上,此控件继承自ItemsControl,如图:
它本质上也是用MapLayer来呈现地图元素,比直接使用MapLayer更方便数据绑定。
3. 图钉
此元素是地图开发中最重要的元素之一,因为我们要在地图上标注某个坐标,比如某个建筑或者我们的位置,实际上就是创建了一个图钉,图钉用Pushpin来表示,同样看一下基类,如图:
非常简单,非常直接!Pushpin甚至比常见控件Button还简单,直接继承自ContentControl。说明我们可以通过Content属性修改图钉的内容,也可以通过ControlTemplate彻底改变图钉的样式,这个和改变Button的样式没什么区别,除此以外Location属性记录的是图钉的位置坐标,因为坐标实际上是一个点,而图钉在地图上显示的时候是一个区域,所以PositionOrigin可以设定该区域和坐标点的相对位置。
4. 地图多边形
为了在地图上勾勒出某个区域,比如北京地区,肯定需要根据经纬坐标来画一个多边形,犹如siverlight中的Polygon一样。
MapPolygon类作用就在于此,查看基类:
发现Locations就是多边形顶点的集合。
同时MapPolygon也继承自ContentControl,因而和Pushpin一样,可以通过Content来设置内容,比如显示区域的名称。
四、地图服务
为了完成一些诸如线路搜索等功能,微软以WCF的形式提供了4个地图服务,分别如下:
- Geocode Service:
http://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc
此服务主要作用是查询地图中对象的地理坐标或者根据地理坐标查询地图中对象
2. Imagery Service:
http://dev.virtualearth.net/webservices/v1/imageryservice/imageryservice.svc
此服务主要用于根据条件如地理坐标或缩放级别得到完整的地图图像
3. Route Service:
http://dev.virtualearth.net/webservices/v1/routeservice/routeservice.svc
此服务主要用于根据一些条件比如某些指定的地点或标志查询出路线
4. Search Service:
http://dev.virtualearth.net/webservices/v1/searchservice/searchservice.svc
此服务主要用于根据条件如关键词查询目标
五、地图汉化
使用Map控件加载出来的地图是英文地图,肯定是不符合国情的,要解决这个问题,似乎除了微软今后提供支持中文地图的Map控件外,也没有太好的办法。以下是通过自定义图层覆盖默认图层的方式实现的汉化。
在Load事件处理函数中加入类似如下语句;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
MapTileLayer tileLayer = new MapTileLayer(); tileLayer.Width = this.map1.ActualWidth; tileLayer.Height = this.map1.ActualHeight; TileSource tileSource = new TileSource("http://r2.tiles.ditu.live.com/tiles/r{quadkey}.png?g=4"); tileLayer.TileSources.Add(tileSource); map1.Children.Add(tileLayer);
注:将tileLayer设置成 半透明
tileLayer.Opacity = 0.5;
可以发现,半透明的中文版Bing地图图层后面仍可以看到英文地图,说明默认的英文图层仍然加载了一遍,只是被挡在了中文图层的后面,这样是没有意义的,还影响加载速度,解决的办法是将Map控件的Mode设置MercatorMode,通常我们设置的是MercatorMode的派生类。
六、使用Google地图
Google地图相对来说还是较Bing地图更完善,要在WP中使用Google地图,可以利用上一小节的原理,也是通过加载Google地图图层覆盖默认图层来实现的。
思路如下:
先扩展TileSource类,用来加载Google地图,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class GoogleTileSource : TileSource { public GoogleTileSource() : base("http://mt{0}.google.com/vt/lyrs={1}&z={2}&x={3}&y={4}") { } public override Uri GetUri(int x, int y, int zoomLevel) { if (zoomLevel > 0) { var Url = string.Format(UriFormat, 0, "m", zoomLevel, x, y); return new Uri(Url); } return null; } }
然后将上一节的代码稍作修改:
TileSource tileSource = new TileSource("http://r2.tiles.ditu.live.com/tiles/r{quadkey}.png?g=4")
改为
TileSource tileSource = new GoogleTileSource();
运行后,发现加载的地图就变成了Google的地图了。
此外,网上有一个封装好的库googlemaps.dll,使用方式很简单,类似如下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<my:Map Name="map1"> <my:Map.Children> <my:MapTileLayer> <my:MapTileLayer.TileSources> <GoogleTileSource:GoogleTile TileTypes="Street"> </GoogleTileSource:GoogleTile> </my:MapTileLayer.TileSources> </my:MapTileLayer> </my:Map.Children> </my:Map>
关于地图开发的一些基础知识,本文就总结这么多,下一节将结合实例讲解一些常见案例的开发。