Отображение объектов на карте

Примечание

MapControl и службы карт требуют ключ проверки подлинности Maps, который называется MapServiceToken. Дополнительные сведения о получении и установке ключа проверки подлинности карт см. в статье Запрос ключа проверки подлинности карт.

Добавляйте объекты на карту, используя вешки, изображения, фигуры и элементы пользовательского интерфейса XAML. Объект — это определенная точка на карте, представляющая что-нибудь интересное. Например, это может быть расположение компании, города или друга.

Чтобы получить дополнительные сведения об отображении объектов в приложении, скачайте пример карты универсальной платформы для Windows (UWP) из репозитория Windows-universal-samples на веб-сайте GitHub.

Отображение кнопок, изображений и фигур на карте путем добавления объектов MapIcon, MapBillboard, MapPolygon и MapPolyline в коллекцию MapElements объекта MapElementsLayer . Затем добавьте этот объект слоя в коллекцию Layers элемента управления картой.

Примечание

В предыдущих выпусках в этом руководстве рассказывалось, как добавить элементы на карте в коллекцию MapElements. Хотя по-прежнему можно использовать этот подход, вы упустите некоторые преимущества новой модели слоев карты. Дополнительные сведения см. в разделе Работа со слоями данного руководства.

Можно также отобразить элементы пользовательского интерфейса XAML, например Button, HyperlinkButton или TextBlock, на карте, добавляя их в MapItemsControl или качестве Children (дочерних элементов) объекта MapControl.

Если необходимо разместить на карте большое количество элементов, можно наложить на нее динамически перераспределяемые изображения. Сведения о том, как отобразить дороги на карте, см. в статье Отображение маршрутов и направлений.

Добавление вешки

Чтобы показать изображение, например вешку, на карте и при желании добавить к нему текст, используйте класс MapIcon. Можно принять изображение по умолчанию или указать пользовательское изображение с помощью свойства Image. На рисунке ниже показано изображение по умолчанию для объекта MapIcon, у которого не задано значение для свойства Title, с коротким названием, длинным названием и очень длинным названием.

Пример MapIcon с названиями разной длины.

В примере ниже показано, как отобразить карту Сиэтла и добавить объект MapIcon с изображением по умолчанию и необязательным заголовком, чтобы указать расположение башни Спейс-Нидл. Кроме того, в примере показано, как выполнить центровку карты по отношению к значку и увеличить ее масштаб. Общие сведения об использовании элемента управления картой см. в статье Отображение карт с помощью двумерных и трехмерных представлений, а также представлений Streetside.

public void AddSpaceNeedleIcon()
{
    var MyLandmarks = new List<MapElement>();

    BasicGeoposition snPosition = new BasicGeoposition { Latitude = 47.620, Longitude = -122.349 };
    Geopoint snPoint = new Geopoint(snPosition);

    var spaceNeedleIcon = new MapIcon
    {
        Location = snPoint,
        NormalizedAnchorPoint = new Point(0.5, 1.0),
        ZIndex = 0,
        Title = "Space Needle"
    };

    MyLandmarks.Add(spaceNeedleIcon);

    var LandmarksLayer = new MapElementsLayer
    {
        ZIndex = 1,
        MapElements = MyLandmarks
    };

    myMap.Layers.Add(LandmarksLayer);

    myMap.Center = snPoint;
    myMap.ZoomLevel = 14;

}

В этом примере отображаются указанные ниже объекты на карте (изображение по умолчанию находится в центре).

Карта с объектом MapIcon

Указанная ниже строка кода отображает объект MapIcon с пользовательским изображением, сохраненным в папке Assets проекта. Свойство Image объекта MapIcon принимает значение с типом RandomAccessStreamReference. Этому типу требуется оператор using для пространства имен Windows.Storage.Streams.

Примечание

Чтобы обеспечить максимальную производительность при использовании одного и того же изображения для нескольких значков карт, объявите объект RandomAccessStreamReference на уровне страницы или приложения.

    MapIcon1.Image =
        RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/customicon.png"));

При работе с классом MapIcon учитывайте указанные ниже соображения.

  • Свойство Image поддерживает изображения размером не более 2048×2048 пикселей.
  • По умолчанию отображение изображения значка карты не гарантируется. Этот элемент может быть скрыт, если он заслоняет другие элементы или метки на карте. Чтобы он оставался видимым, задайте для свойства CollisionBehaviorDesired значение MapElementCollisionBehavior.RemainVisible.
  • Отображение необязательного свойства Title объекта MapIcon не гарантируется. Если текст не отображается, уменьшите масштаб, уменьшив значение свойства ZoomLevel объекта MapControl.
  • При показе изображения MapIcon, которое указывает определенное местоположение на карте, например вешки или стрелки, попробуйте присвоить значению свойства NormalizedAnchorPoint приблизительное местоположение указателя на изображении. Если для свойства NormalizedAnchorPoint оставить значение по умолчанию (0, 0), которое соответствует верхнему левому углу изображения, то в результате изменений свойства карты ZoomLevel изображение может указывать на другое местоположение.
  • Если Altitude и AltitudeReferenceSystem не заданы явным образом, элемент MapIcon будет размещен на поверхности.

Добавление трехмерной вешки

Трехмерные объекты можно добавлять на карту. Используйте класс MapModel3D для импорта трехмерного объекта из файла в трехмерном производственном формате (3MF).

На этом изображении трехмерные чашки кофе используются для обозначения расположения кофеен в районе.

кружки на картах

Следующий код добавляет чашку кофе на карту путем импорта файла 3MF. Чтобы не усложнять, этот код добавляет изображение в центр карты, но ваш код, вероятно, будет добавлять изображение в определенное расположение.

public async void Add3DMapModel()
{
    var mugStreamReference = RandomAccessStreamReference.CreateFromUri
        (new Uri("ms-appx:///Assets/mug.3mf"));

    var myModel = await MapModel3D.CreateFrom3MFAsync(mugStreamReference,
        MapModel3DShadingOption.Smooth);

    myMap.Layers.Add(new MapElementsLayer
    {
       ZIndex = 1,
       MapElements = new List<MapElement>
       {
          new MapElement3D
          {
              Location = myMap.Center,
              Model = myModel,
          },
       },
    });
}

Добавление образа.

Показывайте большие изображения, связанные с расположениями на карте, например фотографии ресторана или ориентира. Когда пользователи отдаляют карту, изображение пропорционально уменьшается, чтобы пользователь мог видеть расширенный участок карты. Это немного отличается от элемента MapIcon, который помечает определенное расположение, обычно имеет небольшой размер и сохраняет свой размер, когда пользователь приближает и отдаляет карту.

Изображение MapBillboard

В следующем коде показан элемент MapBillboard, представленный на рисунке выше.

public void AddLandmarkPhoto()
{
    // Create MapBillboard.

    RandomAccessStreamReference mapBillboardStreamReference =
        RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/billboard.jpg"));

    var mapBillboard = new MapBillboard(myMap.ActualCamera)
    {
        Location = myMap.Center,
        NormalizedAnchorPoint = new Point(0.5, 1.0),
        Image = mapBillboardStreamReference
    };

    // Add MapBillboard to a layer on the map control.

    var MyLandmarkPhotos = new List<MapElement>();

    MyLandmarkPhotos.Add(mapBillboard);

    var LandmarksPhotoLayer = new MapElementsLayer
    {
        ZIndex = 1,
        MapElements = MyLandmarkPhotos
    };

    myMap.Layers.Add(LandmarksPhotoLayer);
}

В этом коде есть три фрагмента, которые заслуживают более тщательного изучения: изображение, опорная камера и свойство NormalizedAnchorPoint.

Image

В этом примере показано пользовательское изображение, сохраненное в папку проекта Assets. Свойство Image объекта MapBillboard принимает значение с типом RandomAccessStreamReference. Этому типу требуется оператор using для пространства имен Windows.Storage.Streams.

Примечание

Чтобы обеспечить максимальную производительность при использовании одного и того же изображения для нескольких значков карт, объявите объект RandomAccessStreamReference на уровне страницы или приложения.

Опорная камера

Так как изображение MapBillboard масштабируется при изменении свойства ZoomLevel карты, важно определить, при каком положении регулятора ZoomLevel изображение отображается в исходном масштабе. Это положение определяется в опорной камере MapBillboard, и для его настройки необходимо передать объект MapCamera в конструктор MapBillboard.

Вы можете определить требуемое положение в Geopoint и затем использовать эту точку Geopoint для создания объекта MapCamera. Однако в этом примере мы просто используем объект MapCamera, возвращаемый свойством ActualCamera элемента управления картой. Это внутренняя камера карты. Текущее положение этой камеры становится положением опорной камеры, то есть тем положением, в котором изображение MapBillboard отображается в исходном масштабе.

Если ваше приложение предоставляет пользователям возможность уменьшить масштаб на карте, размер изображения уменьшается, поскольку внутренняя камера карты поднимается над землей, а изображение в его исходном размере остается неподвижным с привязкой к опорной камере.

NormalizedAnchorPoint

NormalizedAnchorPoint является точкой изображения, привязанной к свойству Location объекта MapBillboard. Точка с координатами 0,5, 1 — центр нижнего края изображения. Поскольку мы присвоили свойству Location объекта MapBillboard значение, соответствующее центру элемента управления картой, нижний край изображения будет привязан к центру элемента управления картой. Если изображение должно отображаться по центру прямо над точкой, задайте для NormalizedAnchorPoint значение 0.5,0.5.

Добавление фигуры

Для отображения многоточечной фигуры на карте используйте класс MapPolygon. В показанном ниже фрагменте из примера карты UWP показано, как отобразить красное поле с синей рамкой на карте.

public void HighlightArea()
{
    // Create MapPolygon.

    double centerLatitude = myMap.Center.Position.Latitude;
    double centerLongitude = myMap.Center.Position.Longitude;

    var mapPolygon = new MapPolygon
    {
        Path = new Geopath(new List<BasicGeoposition> {
                    new BasicGeoposition() {Latitude=centerLatitude+0.0005, Longitude=centerLongitude-0.001 },
                    new BasicGeoposition() {Latitude=centerLatitude-0.0005, Longitude=centerLongitude-0.001 },
                    new BasicGeoposition() {Latitude=centerLatitude-0.0005, Longitude=centerLongitude+0.001 },
                    new BasicGeoposition() {Latitude=centerLatitude+0.0005, Longitude=centerLongitude+0.001 },
                }),
        ZIndex = 1,
        FillColor = Colors.Red,
        StrokeColor = Colors.Blue,
        StrokeThickness = 3,
        StrokeDashed = false,
    };

    // Add MapPolygon to a layer on the map control.
    var MyHighlights = new List<MapElement>();

    MyHighlights.Add(mapPolygon);

    var HighlightsLayer = new MapElementsLayer
    {
        ZIndex = 1,
        MapElements = MyHighlights
    };

    myMap.Layers.Add(HighlightsLayer);
}

Добавление линии

Для отображения линии на карте используйте класс MapPolyline. В показанном ниже фрагменте из примера карты UWP показано, как отобразить пунктирную линию на карте.

public void DrawLineOnMap()
{
    // Create Polyline.

    double centerLatitude = myMap.Center.Position.Latitude;
    double centerLongitude = myMap.Center.Position.Longitude;
    var mapPolyline = new MapPolyline
    {
        Path = new Geopath(new List<BasicGeoposition> {
                    new BasicGeoposition() {Latitude=centerLatitude-0.0005, Longitude=centerLongitude-0.001 },
                    new BasicGeoposition() {Latitude=centerLatitude+0.0005, Longitude=centerLongitude+0.001 },
                }),
        StrokeColor = Colors.Black,
        StrokeThickness = 3,
        StrokeDashed = true,
    };

   // Add Polyline to a layer on the map control.

   var MyLines = new List<MapElement>();

   MyLines.Add(mapPolyline);

   var LinesLayer = new MapElementsLayer
   {
       ZIndex = 1,
       MapElements = MyLines
   };

   myMap.Layers.Add(LinesLayer);

}

Добавление XAML

Для отображения настраиваемых элементов пользовательского интерфейса на карте используйте XAML. Чтобы расположить XAML на карте, укажите расположение и нормализованную точку привязки XAML.

  • Чтобы задать местоположение на карте, где необходимо разместить XAML, вызовите метод SetLocation.
  • Чтобы настроить относительное местоположение в XAML, соответствующее указанному местоположению, вызовите метод SetNormalizedAnchorPoint.

В примере ниже показано, как отобразить карту Сиэтла и добавить элемент управления XAML Border, чтобы указать местоположение башни Спейс-Нидл. Кроме того, в примере показано, как выполнить центровку карты по отношению к области и увеличить ее масштаб. Общие сведения об использовании элемента управления картой см. в статье Отображение карт с помощью двумерных и трехмерных представлений, а также представлений Streetside.

private void displayXAMLButton_Click(object sender, RoutedEventArgs e)
{
   // Specify a known location.
   BasicGeoposition snPosition = new BasicGeoposition { Latitude = 47.620, Longitude = -122.349 };
   Geopoint snPoint = new Geopoint(snPosition);

   // Create a XAML border.
   Border border = new Border
   {
      Height = 100,
      Width = 100,
      BorderBrush = new SolidColorBrush(Windows.UI.Colors.Blue),
      BorderThickness = new Thickness(5),
   };

   // Center the map over the POI.
   MapControl1.Center = snPoint;
   MapControl1.ZoomLevel = 14;

   // Add XAML to the map.
   MapControl1.Children.Add(border);
   MapControl.SetLocation(border, snPoint);
   MapControl.SetNormalizedAnchorPoint(border, new Point(0.5, 0.5));
}

В этом примере показано, как отобразить синюю рамку на карте.

Снимок экрана с xaml, отображенным в достопримечательности на карте

В примерах ниже показано, как добавить элементы пользовательского интерфейса XAML непосредственно в разметку XAML страницы, используя привязку данных. Как и другие элементы XAML, отображающие содержимое, Children — это свойство содержимого по умолчанию объекта MapControl, и его не нужно явно задавать в разметке XAML.

В этом примере показано, как отобразить два элемента управления XAML в качестве неявных потомков класса MapControl. Эти элементы управления отображаются на карте с привязкой расположений к данным.

<maps:MapControl>
    <TextBox Text="Seattle" maps:MapControl.Location="{x:Bind SeattleLocation}"/>
    <TextBox Text="Bellevue" maps:MapControl.Location="{x:Bind BellevueLocation}"/>
</maps:MapControl>

Задайте эти расположения с помощью свойств в файле кода программной части.

public Geopoint SeattleLocation { get; set; }
public Geopoint BellevueLocation { get; set; }

В этом примере показано, как отобразить два элемента управления XAML, содержащиеся в MapItemsControl. Эти элементы управления отображаются на карте в расположениях, обусловленных данными.

<maps:MapControl>
  <maps:MapItemsControl>
    <TextBox Text="Seattle" maps:MapControl.Location="{x:Bind SeattleLocation}"/>
    <TextBox Text="Bellevue" maps:MapControl.Location="{x:Bind BellevueLocation}"/>
  </maps:MapItemsControl>
</maps:MapControl>

В этом примере показано, как отобразить коллекцию элементов XAML, связанных с классом MapItemsControl.

<maps:MapControl x:Name="MapControl" MapTapped="MapTapped" MapDoubleTapped="MapTapped" MapHolding="MapTapped">
  <maps:MapItemsControl ItemsSource="{x:Bind LandmarkOverlays}">
      <maps:MapItemsControl.ItemTemplate>
          <DataTemplate>
              <StackPanel Background="Black" Tapped ="Overlay_Tapped">
                  <TextBlock maps:MapControl.Location="{Binding Location}" Text="{Binding Title}"
                    maps:MapControl.NormalizedAnchorPoint="0.5,0.5" FontSize="20" Margin="5"/>
              </StackPanel>
          </DataTemplate>
      </maps:MapItemsControl.ItemTemplate>
  </maps:MapItemsControl>
</maps:MapControl>

Свойство ItemsSource в приведенном выше примере привязано к свойство типа IList в файле кода программной части.

public sealed partial class Scenario1 : Page
{
    public IList LandmarkOverlays { get; set; }

    public MyClassConstructor()
    {
         SetLandMarkLocations();
         this.InitializeComponent();   
    }

    private void SetLandMarkLocations()
    {
        LandmarkOverlays = new List<MapElement>();

        var pikePlaceIcon = new MapIcon
        {
            Location = new Geopoint(new BasicGeoposition
            { Latitude = 47.610, Longitude = -122.342 }),
            Title = "Pike Place Market"
        };

        LandmarkOverlays.Add(pikePlaceIcon);

        var SeattleSpaceNeedleIcon = new MapIcon
        {
            Location = new Geopoint(new BasicGeoposition
            { Latitude = 47.6205, Longitude = -122.3493 }),
            Title = "Seattle Space Needle"
        };

        LandmarkOverlays.Add(SeattleSpaceNeedleIcon);
    }
}

Работа со слоями

В примерах в этом руководстве элементы добавляются в коллекцию MapElementLayers. Затем рассказывается, как добавить эту коллекцию в свойство Layers элемента управления картой. В предыдущих выпусках в этом руководстве рассказывалось, как добавить элементы на карте в коллекцию MapElements:

var pikePlaceIcon = new MapIcon
{
    Location = new Geopoint(new BasicGeoposition
    { Latitude = 47.610, Longitude = -122.342 }),
    NormalizedAnchorPoint = new Point(0.5, 1.0),
    ZIndex = 0,
    Title = "Pike Place Market"
};

myMap.MapElements.Add(pikePlaceIcon);

Хотя по-прежнему можно использовать этот подход, вы упустите некоторые преимущества новой модели слоев карты. Группируя элементы в слои, можно управлять каждым слоем независимо друг от друга. Например, каждый слой имеет собственный набор событий, поэтому можно реагировать на событие в определенном слое и выполнить действие для этого события.

Также можно привязать XAML непосредственно к MapLayer. Это то, что вы не можете сделать с помощью коллекции MapElements .

Один из способов, как это можно сделать, — использовать класс модели представления, код программной части XAML-страницы, а также XAML-страницу.

Класс модели представления

public class LandmarksViewModel
{
    public ObservableCollection<MapLayer> LandmarkLayer
        { get; } = new ObservableCollection<MapLayer>();

    public LandmarksViewModel()
    {
        var MyElements = new List<MapElement>();

        var pikePlaceIcon = new MapIcon
        {
            Location = new Geopoint(new BasicGeoposition
            { Latitude = 47.610, Longitude = -122.342 }),
            Title = "Pike Place Market"
        };

        MyElements.Add(pikePlaceIcon);

        var LandmarksLayer = new MapElementsLayer
        {
            ZIndex = 1,
            MapElements = MyElements
        };

        LandmarkLayer.Add(LandmarksLayer);         
    }

Код программной части XAML-страницы

Подключите класс модели представления к коду программной части страницы.

public LandmarksViewModel ViewModel { get; set; }

public myMapPage()
{
    this.InitializeComponent();
    this.ViewModel = new LandmarksViewModel();
}

XAML-страница

На XAML-странице выполните привязку к свойству в классе модели представления, которое возвращает слой.

<maps:MapControl
    x:Name="myMap" TransitFeaturesVisible="False" Loaded="MyMap_Loaded" Grid.Row="2"
    MapServiceToken="Your token" Layers="{x:Bind ViewModel.LandmarkLayer}"/>