在一些应用中,需要有地图位置定位及前往该位置的路径导航功能。地图功能可以调用Windows地图实现。但调用Windows地图需要涉及应用切换,对于用户使用并不友好。需要通过在应用中加入地图来实现。
1 . 直接调用Windows地图
直接调用Windows地图功能使用特定的URI,包括bingmaps:,ms-drive-to:及ms-walk-to: 。具体的URI说明请参考说明文档。
给一个例子,步行从使用者所在的位置(定位)导航到给定坐标,名叫“北山”的地点:
Uri uri = new Uri(@"ms-walk-to:?destination.latitude=31.5035866365965&destination.longitude=112.523597655425&destination.name=北山");
var launcherOptions = new Windows.System.LauncherOptions();
launcherOptions.TargetApplicationPackageFamilyName = "Microsoft.WindowsMaps_8wekyb3d8bbwe";
var success = await Windows.System.Launcher.LaunchUriAsync(uri, launcherOptions);
2 .显示地图
在应用中显示地图,首先需要注册一个必应地图开发者账号,创建应用,获取密钥。
地图使用MapControl控件,在Xaml中引入命名空间。
xmlns:Maps="using:Windows.UI.Xaml.Controls.Maps"
添加地图控件。MapServiceToken
为你的密钥。
<Maps:MapControl
x:Name="MapControl1"
ZoomInteractionMode="GestureAndControl"
TiltInteractionMode="GestureAndControl"
MapServiceToken=""/>
3 .设置地图信息
设置地图中心,缩放比例等信息。
//地图中心
BasicGeoposition cityPosition = new BasicGeoposition() { Latitude = 31.5035866365965, Longitude = 112.523597655425 };
Geopoint cityCenter = new Geopoint(cityPosition);
MapControl1.Center = cityCenter;
//其他信息
MapControl1.ZoomLevel = 15;
MapControl1.LandmarksVisible = true;
显示地图及设置地图信息更详细的说明,可以参考文档。文档后面的街景视图等内容,只有国外的区域能用,基本可以不用考虑。
4 .定位
获取用户的位置信息,需要定位权限。首先要在应用包设置中选中“位置”,允许权限。
当用户第一次使用此应用定位时,还会弹出对话框,是否允许使用位置信息。该权限可以在设备的设置->隐私->位置中更改。
Geopoint MyLoc = null;
var accessStatus = await Geolocator.RequestAccessAsync();
switch (accessStatus)
{
//获取位置权限成功
case GeolocationAccessStatus.Allowed:
Geolocator geolocator = new Geolocator();
Geoposition pos = await geolocator.GetGeopositionAsync();
MyLoc = pos.Coordinate.Point;
break;
case GeolocationAccessStatus.Denied:
break;
case GeolocationAccessStatus.Unspecified:
break;
}
5 .添加地图标记
对于给定的坐标在地图上添加标记。
MapIcon mapIcon1 = new MapIcon();
mapIcon1.Location = cityCenter; //位置坐标
mapIcon1.NormalizedAnchorPoint = new Point(0.5, 1.0);
mapIcon1.Title = "北山";
mapIcon1.ZIndex = 0;
mapIcon1.Image = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/logosmall.png")); //使用特定图片作为地图标记,不写这条语句则使用默认标记
添加直线及以XAML元素作为地图标记的方法,参考文档。
6 .导航
给定两个位置坐标,获取驾车路线或者步行路线。
MapRouteFinderResult routeResult =
await MapRouteFinder.GetDrivingRouteAsync(
MyLoc, //位置1
cityCenter, //位置2
MapRouteOptimization.Time, //以时间最少为优先选择条件
MapRouteRestrictions.None); //无其他限制条件(不走高速等)
if (routeResult.Status == MapRouteFinderStatus.Success)
{
double length = routeResult.Route.LengthInMeters;
//距离
Tb_Distance.Text = length < 1000 ? length.ToString() + "m" : (length / 1000).ToString("0.00") + "km";
//时间
Tb_Time.Text = routeResult.Route.EstimatedDuration.TotalMinutes.ToString("0.00") + "分钟";
//在地图上标记出此路线(路线以给定颜色高亮显示)
MapRouteView viewOfRoute = new MapRouteView(routeResult.Route);
viewOfRoute.RouteColor = Color.FromArgb(255, 26, 188, 156);
MapControl1.Routes.Clear();
MapControl1.Routes.Add(viewOfRoute);
await MapControl1.TrySetViewBoundsAsync(
routeResult.Route.BoundingBox,
ull,
Windows.UI.Xaml.Controls.Maps.MapAnimationKind.None);
//自定义类,用于存放路径中部分有用的信息。
List RI = new List();
System.Text.StringBuilder routeInfo = new System.Text.StringBuilder();
foreach (MapRouteLeg leg in routeResult.Route.Legs)
{
foreach (MapRouteManeuver maneuver in leg.Maneuvers)
{
RI.Add(new RouteItem(maneuver.InstructionText, maneuver.LengthInMeters + "m", maneuver.StartingPoint));
}
}
}
else if(routeResult.Status == MapRouteFinderStatus.NetworkFailure);
RouteItem
定义如下:
public class RouteItem
{
public RouteItem(string direction, string length, Geopoint point)
{
Direction = direction;
Length = length;
Point = point;
}
public string Direction { get; set; } //逐步导航信息
public string Length { get; set; } //该步骤执行后走的距离,到下一步骤
public Geopoint Point { get; set; } //执行该步骤的起始点坐标
}
执行步行导航,只需要将MapRouteFinder.GetDrivingRouteAsync替换为
MapRouteFinderResult routeResult =
await MapRouteFinder.GetWalkingRouteAsync(
MyLoc,
cityCenter);
其他代码相同。
获取导航路径这一部分可以参考文档。
7 .逐步导航的界面呈现
XAML中定义Item模板。绑定上一步中获取的逐步导航信息,到界面呈现。
<DataTemplate x:Key="RouteTemplate" x:DataType="local:RouteItem">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*">ColumnDefinition>
<ColumnDefinition Width="auto">ColumnDefinition>
Grid.ColumnDefinitions>
<TextBlock Text="{x:Bind Direction}" Grid.Column="0" TextWrapping="Wrap" MaxWidth="300" HorizontalAlignment="Left">TextBlock>
<TextBlock Text="{x:Bind Length}" Grid.Column="1" TextWrapping="Wrap" HorizontalAlignment="Right">TextBlock>
Grid>
DataTemplate>
呈现结果为下图所示的列表。
当点击一个列表项的时候,触发事件。在地图上标记该步骤。
private void Lv_Route_ItemClick(object sender, ItemClickEventArgs e)
{
var item = e.ClickedItem as RouteItem;
//清除已有的标记
MapControl1.MapElements.Clear();
//添加新的点标记
MapIcon mapIcon1 = new MapIcon();
mapIcon1.Location = item.Point;
mapIcon1.NormalizedAnchorPoint = new Point(0.5, 1.0);
mapIcon1.Title = item.Direction;
mapIcon1.ZIndex = 0;
MapControl1.MapElements.Add(mapIcon1);
}
8 .实时导航
实时导航需要响应用户位置更新,并更新导航结果。这个功能在一般的附加地图位置分享功能的应用中,几乎不需要用到。只有在以地图为主的应用中用到。如果需要用到这一功能,建议跳转到Windows地图应用来实现。如果要自己写这一功能,可以参考文档,不再介绍。
代码通过Visual Studio 2017测试。