使用 2D、3D 和街景视图显示地图

重要

必应地图企业版服务停用

Windows.Services.Maps 命名空间中的 UWP MapControl 和地图服务依赖于必应地图。 必应地图企业版已弃用,并且将停用,此时 MapControl 和服务将不再接收数据。

有关详细信息,请参阅必应地图开发人员中心和必应地图文档。 可以在轻型可消除窗口中显示地图,称为地图 放置卡 或在功能齐全的地图控件中显示地图。

下载地图示例以试用本指南中所述的一些功能。

在名片中显示地图

可以在上方、下方或 UI 元素的一侧或用户触摸的应用的一侧显示轻量级弹出窗口内的地图。 地图可以显示与应用中的信息相关的城市或地址。

此名片显示西雅图市。

显示西雅图市的名片

下面是使西雅图显示在按钮下方的一个名片中的代码。

private void Seattle_Click(object sender, RoutedEventArgs e)
{
    Geopoint seattlePoint = new Geopoint
        (new BasicGeoposition { Latitude = 47.6062, Longitude = -122.3321 });

    PlaceInfo spaceNeedlePlace = PlaceInfo.Create(seattlePoint);

    FrameworkElement targetElement = (FrameworkElement)sender;

    GeneralTransform generalTransform =
        targetElement.TransformToVisual((FrameworkElement)targetElement.Parent);

    Rect rectangle = generalTransform.TransformBounds(new Rect(new Point
        (targetElement.Margin.Left, targetElement.Margin.Top), targetElement.RenderSize));

    spaceNeedlePlace.Show(rectangle, Windows.UI.Popups.Placement.Below);
}

此名片显示西雅图空间针的位置。

显示空间针位置的名片

下面是使 Space Needle 出现在按钮下方的一个名片中的代码。

private void SpaceNeedle_Click(object sender, RoutedEventArgs e)
{
    Geopoint spaceNeedlePoint = new Geopoint
        (new BasicGeoposition { Latitude = 47.6205, Longitude = -122.3493 });

    PlaceInfoCreateOptions options = new PlaceInfoCreateOptions();

    options.DisplayAddress = "400 Broad St, Seattle, WA 98109";
    options.DisplayName = "Seattle Space Needle";

    PlaceInfo spaceNeedlePlace =  PlaceInfo.Create(spaceNeedlePoint, options);

    FrameworkElement targetElement = (FrameworkElement)sender;

    GeneralTransform generalTransform =
        targetElement.TransformToVisual((FrameworkElement)targetElement.Parent);

    Rect rectangle = generalTransform.TransformBounds(new Rect(new Point
        (targetElement.Margin.Left, targetElement.Margin.Top), targetElement.RenderSize));

    spaceNeedlePlace.Show(rectangle, Windows.UI.Popups.Placement.Below);
}

在控件中显示地图

使用地图控件在应用中显示丰富的可自定义地图数据。 地图控件可以显示路线图、空中、3D、视图、路线、搜索结果和交通。 在地图上,可以显示用户的位置、路线和兴趣点。 地图还可以显示空中 3D 视图、街景视图、交通、交通、交通和当地企业。

如果希望应用中的地图允许用户查看特定于应用的地理信息或常规地理信息,请使用地图控件。 在应用中拥有地图控件意味着用户不必在应用外部获取该信息。

注意

如果你不介意用户走出应用,请考虑使用Windows 地图应用提供该信息。 应用可以启动Windows 地图应用以显示特定的地图、路线和搜索结果。 有关详细信息,请参阅启动 Windows 地图应用

向应用添加地图控件

通过添加 MapControl 在 XAML 页面上显示地图。 若要使用 MapControl,必须在 XAML 页或代码中声明 Windows.UI.Xaml.Controls.Maps 命名空间。 如果从工具箱中拖动控件,则会自动添加此命名空间声明。 如果手动将 MapControl 添加到 XAML 页面,则必须在页面顶部手动添加命名空间声明。

以下示例显示基本地图控件,并配置地图以显示缩放和倾斜控件,以及接受触摸输入。

<Page
    x:Class="MapsAndLocation1.DisplayMaps"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MapsAndLocation1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:Maps="using:Windows.UI.Xaml.Controls.Maps"
    mc:Ignorable="d">

 <Grid x:Name="pageGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Maps:MapControl
       x:Name="MapControl1"            
       ZoomInteractionMode="GestureAndControl"
       TiltInteractionMode="GestureAndControl"   
       MapServiceToken="EnterYourAuthenticationKeyHere"/>

 </Grid>
</Page>

如果在代码中添加映射控件,则必须在代码文件的顶部手动声明命名空间。

using Windows.UI.Xaml.Controls.Maps;
...

// Add the MapControl and the specify maps authentication key.
MapControl MapControl2 = new MapControl();
MapControl2.ZoomInteractionMode = MapInteractionMode.GestureAndControl;
MapControl2.TiltInteractionMode = MapInteractionMode.GestureAndControl;
MapControl2.MapServiceToken = "EnterYourAuthenticationKeyHere";
pageGrid.Children.Add(MapControl2);

获取和设置映射身份验证密钥

在使用 MapControl 和地图服务之前,必须将地图身份验证密钥指定为 MapServiceToken 属性的值 在前面的示例中,将替换为EnterYourAuthenticationKeyHere从必应地图开发人员中心获取的密钥。 文本 警告:在指定地图身份验证密钥之前,未指定 MapServiceToken 继续显示在控件下方。 有关获取和设置地图身份验证密钥的详细信息,请参阅请求地图身份验证密钥

设置地图的位置

将地图指向所需的任何位置或使用用户的当前位置。

设置地图的起始位置

通过在代码中指定 MapControl 的中心属性或绑定 XAML 标记中的属性来设置在地图上显示的位置。 以下示例显示一个地图,其中西雅图市作为中心。

注意

由于字符串无法转换为 Geopoint,因此除非使用数据绑定,否则无法在 XAML 标记中为 Center 属性指定值。 (此限制也适用于 MapControl.Location attached 属性。)

protected override void OnNavigatedTo(NavigationEventArgs e)
{
   // Specify a known location.
   BasicGeoposition cityPosition = new BasicGeoposition() { Latitude = 47.604, Longitude = -122.329 };
   Geopoint cityCenter = new Geopoint(cityPosition);

   // Set the map location.
   MapControl1.Center = cityCenter;
   MapControl1.ZoomLevel = 12;
   MapControl1.LandmarksVisible = true;
}

地图控件的示例。

设置地图的当前位置

在应用可以访问用户的位置之前,应用必须调用 RequestAccessAsync 方法。 此时,你的应用必须位于前台,并且 RequestAccessAsync 必须从 UI 线程中进行调用。 除非用户向你的应用授予访问其位置的权限,否则你的应用将无法访问位置数据。

使用 Geolocator 类的 GetGeopositionAsync 方法获取设备的当前位置(如果位置可用)。 若要获取相应的 Geopoint,请使用地理位置地理协调的 Point 属性。 有关详细信息,请参阅 “获取当前位置”。

// Set your current location.
var accessStatus = await Geolocator.RequestAccessAsync();
switch (accessStatus)
{
   case GeolocationAccessStatus.Allowed:

      // Get the current location.
      Geolocator geolocator = new Geolocator();
      Geoposition pos = await geolocator.GetGeopositionAsync();
      Geopoint myLocation = pos.Coordinate.Point;

      // Set the map location.
      MapControl1.Center = myLocation;
      MapControl1.ZoomLevel = 12;
      MapControl1.LandmarksVisible = true;
      break;

   case GeolocationAccessStatus.Denied:
      // Handle the case  if access to location is denied.
      break;

   case GeolocationAccessStatus.Unspecified:
      // Handle the case if  an unspecified error occurs.
      break;
}

在地图上显示设备的位置时,请考虑显示图形,并根据位置数据的准确性设置缩放级别。 有关详细信息,请参阅 位置感知应用的指南。

更改地图的位置

若要更改 2D 映射中显示的位置,请调用 TrySetViewAsync 方法的重载之一。 使用该方法为 CenterZoomLevelHeadingPitch 指定新值。 还可以通过提供 MapAnimationKind 枚举中的常量来指定要在视图更改时使用的可选动画。

若要更改 3D 映射的位置,请改用 TrySetSceneAsync 方法。 有关详细信息,请参阅 显示空中 3D 视图

调用 TrySetViewBoundsAsync 方法,在地图上显示 GeoboundingBox 的内容。 例如,使用此方法在地图上显示路线或部分路线。 有关详细信息,请参阅 在地图上显示路线和路线。

更改地图的外观

若要自定义地图的外观,请将地图控件的 StyleSheet 属性设置为任何现有的 MapStyleSheet 对象。

myMap.StyleSheet = MapStyleSheet.RoadDark();

深色样式地图

还可以使用 JSON 来定义自定义样式,然后使用该 JSON 创建 MapStyleSheet 对象。

可以使用地图样式表编辑器应用程序以交互方式创建样式表 JSON。

myMap.StyleSheet = MapStyleSheet.ParseFromJson(@"
    {
        ""version"": ""1.0"",
        ""settings"": {
            ""landColor"": ""#FFFFFF"",
            ""spaceColor"": ""#000000""
        },
        ""elements"": {
            ""mapElement"": {
                ""labelColor"": ""#000000"",
                ""labelOutlineColor"": ""#FFFFFF""
            },
            ""water"": {
                ""fillColor"": ""#DDDDDD""
            },
            ""area"": {
                ""fillColor"": ""#EEEEEE""
            },
            ""political"": {
                ""borderStrokeColor"": ""#CCCCCC"",
                ""borderOutlineColor"": ""#00000000""
            }
        }
    }
");

自定义样式地图

有关完整的 JSON 条目引用,请参阅 地图样式表参考

可以从现有工作表开始,然后使用 JSON 替代所需的任何元素。 此示例以现有样式开头,并使用 JSON 仅更改水区的颜色。

 MapStyleSheet \customSheet = MapStyleSheet.ParseFromJson(@"
    {
        ""version"": ""1.0"",
        ""elements"": {
            ""water"": {
                ""fillColor"": ""#DDDDDD""
            }
        }
    }
");

MapStyleSheet builtInSheet = MapStyleSheet.RoadDark();

myMap.StyleSheet = MapStyleSheet.Combine(new List<MapStyleSheet> { builtInSheet, customSheet });

组合样式图

注意

在第二个样式表中定义的样式将覆盖第一个样式。

设置方向和透视

放大、缩小、旋转和倾斜地图的相机,以仅获取所需效果的合适角度。 请尝试这些属性。

  • 通过设置 Center 属性将地图的中心设置为地理点。
  • 通过将 ZoomLevel 属性设置为介于 1 到 20 之间的值来设置地图的缩放级别
  • 通过设置“标题”属性设置地图的旋转,其中 0 或 360 度 = North,90 = East,180 = South,270 = West。
  • 通过将 DesiredPitch 属性设置为介于 0 到 65 度之间的值来设置地图的倾斜

显示和隐藏地图功能

通过设置 MapControl 的以下属性的值来显示或隐藏地图功能,如道路和地标。

有关如何在 MapControl显示图钉、形状和 XAML 控件的信息,请参阅地图上的显示兴趣点(POI)。

显示街景视图

街景视图是显示在地图控件顶部的位置的街道级别视角。

地图控件的街景视图的示例。

考虑“内部”体验,街景视图与最初显示在地图控件中的地图分开。 例如,更改街景视图中的位置不会更改街道视图“下”地图的位置或外观。 关闭街边视图(单击 控件右上角的 X )后,原始地图保持不变。

显示街景视图

  1. 通过检查 IsStreetsideSupported 来确定设备上是否支持街景视图。
  2. 如果支持 Streetside 视图,请通过调用 FindNearbyAsync 在指定位置附近创建 StreetsidePanorama。
  3. 通过检查 StreetsidePanorama 是否不为 null 来确定附近全景是否已找到
  4. 如果找到附近的全景,请为地图控件的 CustomExperience 属性创建 StreetsideExperience

此示例演示如何显示类似于上一图像的街景视图。

注意

如果地图控件的大小太小,将不会显示总览图。

private async void showStreetsideView()
{
   // Check if Streetside is supported.
   if (MapControl1.IsStreetsideSupported)
   {
      // Find a panorama near Avenue Gustave Eiffel.
      BasicGeoposition cityPosition = new BasicGeoposition() { Latitude = 48.858, Longitude = 2.295};
      Geopoint cityCenter = new Geopoint(cityPosition);
      StreetsidePanorama panoramaNearCity = await StreetsidePanorama.FindNearbyAsync(cityCenter);

      // Set the Streetside view if a panorama exists.
      if (panoramaNearCity != null)
      {
         // Create the Streetside view.
         StreetsideExperience ssView = new StreetsideExperience(panoramaNearCity);
         ssView.OverviewMapVisible = true;
         MapControl1.CustomExperience = ssView;
      }
   }
   else
   {
      // If Streetside is not supported
      ContentDialog viewNotSupportedDialog = new ContentDialog()
      {
         Title = "Streetside is not supported",
         Content ="\nStreetside views are not supported on this device.",
         PrimaryButtonText = "OK"
      };
      await viewNotSupportedDialog.ShowAsync();            
   }
}

显示空中 3D 视图

使用 MapScene 类指定地图的 3D 透视。 地图场景表示地图中显示的 3D 视图。 MapCamera 类表示将显示此类视图的相机的位置。

MapCamera 位置到地图场景位置的关系图

若要使地图图面上的建筑物和其他特征显示在 3D 中,请将地图控件的 Style 属性设置为 MapStyle.Aerial3DWithRoads。 这是具有 Aerial3DWithRoads 样式的 3D 视图的示例。

三维地图视图的示例。

显示三维视图

  1. 通过检查 Is3DSupported 来确定设备上是否支持 3D 视图。
  2. 如果支持 3D 视图,请将地图控件的 Style 属性设置为 MapStyle.Aerial3DWithRoads。
  3. 使用许多 CreateFrom 方法之一(例如 CreateFromLocationAndRadius CreateFromCamera)创建 MapScene 对象。
  4. 调用 TrySetSceneAsync 以显示 3D 视图。 还可以通过提供 MapAnimationKind 枚举中的常量来指定要在视图更改时使用的可选动画。

此示例演示如何显示三维视图。

private async void display3DLocation()
{
   if (MapControl1.Is3DSupported)
   {
      // Set the aerial 3D view.
      MapControl1.Style = MapStyle.Aerial3DWithRoads;

      // Specify the location.
      BasicGeoposition hwGeoposition = new BasicGeoposition() { Latitude = 43.773251, Longitude = 11.255474};
      Geopoint hwPoint = new Geopoint(hwGeoposition);

      // Create the map scene.
      MapScene hwScene = MapScene.CreateFromLocationAndRadius(hwPoint,
                                                                           80, /* show this many meters around */
                                                                           0, /* looking at it to the North*/
                                                                           60 /* degrees pitch */);
      // Set the 3D view with animation.
      await MapControl1.TrySetSceneAsync(hwScene,MapAnimationKind.Bow);
   }
   else
   {
      // If 3D views are not supported, display dialog.
      ContentDialog viewNotSupportedDialog = new ContentDialog()
      {
         Title = "3D is not supported",
         Content = "\n3D views are not supported on this device.",
         PrimaryButtonText = "OK"
      };
      await viewNotSupportedDialog.ShowAsync();
   }
}

获取有关位置的信息

通过调用 MapControl 的以下方法获取有关地图上位置的信息。

处理交互和更改

通过处理 MapControl 的以下事件处理地图上的用户输入手势。 通过检查 MapInputEventArgs 的 Location Position 属性的值,获取有关地图上地理位置的信息以及视区中发生手势的物理位置。

通过处理控件的 LoadStatusChanged 事件来确定映射是加载还是完全加载。

通过处理 MapControl 的以下事件来处理当用户或应用更改地图设置时发生的更改。

最佳做法建议

  • 使用充足的屏幕空间(或整个屏幕)来显示地图,以便用户不必过度平移和缩放以查看地理信息。

  • 如果地图仅用于显示静态信息视图,则使用较小的地图可能更合适。 如果你使用较小的静态地图,它的尺寸基于可用性 - 足够小,可以节省足够的屏幕空间,但足够大,可以保持清晰。

  • 使用 地图元素在地图场景中嵌入兴趣点;任何其他信息都可以显示为覆盖地图场景的暂时性 UI。