Windows Phone 8.1

Добавление данных приложения в элемент управления Map

Кит Пижиновски

Исходный код можно скачать по ссылке

Продукты и технологии:

Windows Phone 8.1, Visual Studio 2013 Update 3

В статье рассматриваются:

  • добавление элементов управления в элемент управления Map с помощью XAML;
  • связывание данных приложения с элементами управления;
  • масштабирование элементов управления;
  • загрузка карт для автономного использования;
  • обновление загруженных карт.

В своей статье за ноябрь 2014 года по средствам работы с картами, введенными в Windows Phone 8.1, я познакомил вас с элементом управления Map и Mapping Services API. Я показал, как с помощью Map добавить функциональность работы с картами в приложение Windows Phone 8.1, например, для включения изображений, которыми помечаются определенные местоположения, для вычисления географических координат заданного адреса (геокодирование), определение адреса по указанным географическим координатам (обратное геокодирование) и создания инструкций для автомобильных и пеших маршрутов.

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

Добавление элементов управления в Map через XAML

В своей предыдущей статье я использовал код для добавления элемента управления «эллипс» на карту, чтобы обводить кружком определенное местоположение. Это хороший подход, если вам нужен полный контроль. Однако, если вы хотите аннотировать карту множеством различных типов элементов управления, использование кода может привести к необходимости написания весьма громоздкого кода. Добавление элементов управления на карту с помощью XAML более эффективно. Кроме того, подход с XAML гораздо проще, когда возникает необходимость в отображении на карте набора местоположений, используя связывание с данными.

Сначала я покажу, как добавлять элементы управления с помощью XAML и как связывать данные приложения с этими элементами. Затем мы углубимся в связывание с данными и посмотрим, как связать набор местоположений с элементом управления Map.

Добавление базовых XAML-элементов управления Есть два способа добавить элементы управления в Map, чтобы на карте отображались данные приложения: как дочерние по отношению к Map или через MapItemsControl, который содержит нужные элементы управления.

На рис. 1 показано, как добавить элементы управления в качестве дочерних для элемента управления Map. Поскольку Children является свойством для контента по умолчанию в Map, явным образом указывать его в XAML-разметке не требуется. На рис. 2 представлен альтернативный подход, где применяется MapItemControl, содержащий добавляемые элементы управления.

Рис. 1. Добавление элементов управления в качестве дочерних для Map

<Maps:MapControl
  x:Name="myMapControl" Grid.Row="1"
  MapServiceToken="{StaticResource MapServiceTokenString}" >
  <!-- Полоска прогресса используется,
       пока страница загружается -->
  <ProgressBar Name="pbProgressBar" IsIndeterminate="True" Height="560"
    Width="350" />
  <TextBlock Name="tbMessage" Text="{Binding Message}"
    Maps:MapControl.Location="{Binding Location}"  
    Maps:MapControl.NormalizedAnchorPoint="1.0,1.0"
    FontSize="15" Foreground="Black" FontWeight="SemiBold"
    Padding="4,4,4,4"
    Visibility="Collapsed"
    />
  <Image Name="imgMyLocation" Source="Assets/PinkPushPin.png"
    Maps:MapControl.Location="{Binding Location}"
    Maps:MapControl.NormalizedAnchorPoint="0.25, 0.9"
    Height="30" Width="30"
    Visibility="Collapsed" />
</Maps:MapControl>

Рис. 2. Элементы управления, содержащиеся в MapItemControl

<Maps:MapControl
  x:Name="myMapControl"
  MapServiceToken="{StaticResource MapServiceTokenString}">
  <Maps:MapItemsControl>
    <TextBlock Name="tbAddress" Text="{Binding Message}"
      Maps:MapControl.Location="{Binding Location}"
      Maps:MapControl.NormalizedAnchorPoint="1.0,1.0"
      Visibility="Collapsed" />
    <Image Name="imgMyLocation" Source="Assets/PinkPushPin.png"
      Maps:MapControl.Location="{Binding Location}"
      Maps:MapControl.NormalizedAnchorPoint="0.25, 0.9"
      Height="30" Width="30"
      Visibility="Collapsed"/>
  </Maps:MapItemsControl>
</Maps:MapControl>

Если вы применяете вариант с MapItemControl (рис. 2), учтите, что вы не сможете обращаться к таким элементам управления из своего отделенного кода (codebehind). IntelliSense будет принимать имена ваших элементов как допустимые переменные, но в период выполнения эти переменные всегда будут null, и, сославшись на любую из них, вы получите NullReferenceException. Как правило, в MapItemControl включают шаблоны данных, используемые для связывания набора объектов с элементом управления Map. (Это мы обсудим позже.) Поэтому, если вы не осуществляете связывание с набором объектов, лучше добавить свои элементы управления как дочерние для Map (рис. 1).

Связывание с данными Код на рис. 1 использует связывание с данными для задания свойства Location элементов управления Image и TextBlock. Свойство Text в TextBlock также задействует связывание с данными. Если кратко, то свойство Location является подключенным свойством (attached property) типа Geopoint. Оно указывает, где на карте будет размещен элемент управления. Подключенное свойство NormalizedAnchorPoint позволяет тонко настраивать позицию элемента управления. Например, с помощью свойства NormalizedAnchorPoint вы центрируете элемент в некоем местоположении или помещаете его в верхнюю левую часть этого местоположения. Оба эти свойства подробно обсуждались в моей первой статье (msdn.microsoft.com/magazine/dn818495).

Связывание с данными позволяет XAML-элементам управления получать свои значения от нижележащих объектов. Объект, созданный из следующего класса, будет использоваться для хранения значений, нужных XAML-элементам, показанных на рис. 1:

public class LocationEntity
{
  public Geopoint Location { get; set; }
  public string Message { get; set; }
}

Связывание с данными позволяет XAML-элементам управления получать свои значения от нижележащих объектов.

На рис. 3 показан полный код обработчика события OnNavigatedTo для страницы, содержащей элементы управления с рис. 1. (Если страница или представление в приложении требует очень много подготовительной работы, подумайте о размещении этого кода там, где создается модель представления, и о его асинхронном выполнении.) Этот код записывает текущее местоположение устройства в экземпляр класса LocationEntity наряду с коротким сообщением. Заметьте, что объект LocationEntity присваивается свойству DataContext элемента управления Map.

Рис. 3. Обработчик события OnNavigatedTo создает объекты, необходимые для связывания с данными

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
  // Вызываем вспомогательную функцию навигации базового класса
  this.navigationHelper.OnNavigatedTo(e);
  // Получаем текущее местоположение пользователя, чтобы
  // его можно было использовать как центральную точку в Map
  Geolocator geolocator = new Geolocator();
  // Задаем требуемую точность
  geolocator.DesiredAccuracyInMeters = 200;
  // Максимально приемлемый срок кеширования
  // данных о местоположении
  TimeSpan maxAge = new TimeSpan(0, 2, 0);
  // Интервал ожидания, используемый
  // для вызова GetGeopositionAsync
  TimeSpan timeout = new TimeSpan(0, 0, 5);
  Geoposition geoposition = null;
  try
  {
    geoposition = await geolocator.GetGeopositionAsync(maxAge, timeout);
  }
  catch (Exception)
  {
    // Добавьте логику обработки исключения
  }
  // Настраиваем объект LocationEntity
  LocationEntity locationEntity = new LocationEntity();
  locationEntity.Location = geoposition.Coordinate.Point;
  locationEntity.Message = "You are here";
  // Указываем позицию, которая будет находиться в центре Map
  myMapControl.Center = locationEntity.Location;
  // Указываем контекст данных для элементов управления
  // на карте, чтобы механизм связывания с данными работал
  myMapControl.DataContext = locationEntity;
  // Уровень масштабирования
  myMapControl.ZoomLevel = 15;
  // Map выполнил большую часть своей работы.
  // Делаем элементы управления видимыми.
  imgMyLocation.Visibility = Windows.UI.Xaml.Visibility.Visible;
  tbMessage.Visibility = Windows.UI.Xaml.Visibility.Visible;
  // Свертываем полоску прогресса
  pbProgressBar.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}

Несколько советов

В коде на рис. 3 обработчик события OnNavigatedTo выполняет довольно длительную по времени работу. А именно: он вызывает функцию GetGeopositionAsync объекта Geolocator. Эта функция получает текущее местоположение устройства, что необходимо для правильного размещения на карте элементов управления Image и TextBlock. В подобных ситуациях любой элемент управления, добавленный на карту как дочерний через XAML, изначально отображается в верхнем левом углу карты до тех пор, пока вы сможете позиционировать их на карте. Это создает плохое впечатление. Чтобы поправить этот недостаток, просто настройте все добавляемые элементы управления как Collapsed в своей XAML-разметке. Тогда добавленные элементы управления можно будет сделать видимыми только после вычисления позиций элементов управления и подготовки объекта, в котором связываются эти элементы. (Обратитесь к рис. 1 и последним нескольким строкам кода на рис. 3.)

Подумайте о применении свойства DesiredAccuracyInMeters объекта Geolocator. Присвоив ему значение в 100 метров или менее, вы получите наиболее точные из доступных данных. Если устройство оборудовано поддержкой GPS, тогда для определения текущего местоположения устройства будет задействован GPS. Если это значение больше 100 метров, объект Geolocator будет выполнять оптимизацию для экономии аккумуляторов и не станет использовать данные GPS, например сигналы Wi-Fi. Порог в 100 метров может измениться по мере совершенствования устройств, поэтому устанавливайте это свойство в зависимости от требований приложения, а не нижележащего порогового значения, которое инициирует переключение на другое поведение. Наконец, свойство DesiredAccuracyInMeters переопределяет все, что задано в свойстве DesiredAccuracy объекта Geolocator.

Также подумайте об использовании перегруженной версии GetGeopositionAsync, который принимает параметры maximumAge и timeout. Первый — это TimeSpan, указывающий максимально допустимый срок кеширования данных о местоположениях. Второй тоже является TimeSpan и заставит функцию GetGeopositionAsync сгенерировать исключение, если определение текущего местоположения займет больше времени, чем было указано.

Предыдущие два совета должны значительно повысить производительность. Однако в областях с плохими возможностями подключения к Интернету и на устройствах с малым объемом памяти и слишком медленными процессорами элемент управления Map и Mapping Services API могут по-прежнему требовать существенного времени на выполнение операций, что приведет к задержкам. В таких случаях элемент управления Map будет отображать карту земного шара с текущим уровнем масштабирования до тех пор, пока свойству элемента управления Map, контролирующему центральную точку, не будет задано местоположение. Это тоже производит плохое впечатление, так как пользователь должен каким-то способом визуально информироваться о выполнении работы. В XAML на рис. 1 полоска прогресса добавлена как дочерний элемент для Map и сделана видимой. Полоска прогресса настраивается как неопределенная (indeterminate), поскольку точное время, которое займут операции, не известно. Как только вычисляется свойство center карты и присваивается элементу управления Map, полоска прогресса может быть свернута. Согласно рекомендациям, такие полоски прогресса следует всегда размещать в самом верху страницы, и в большинстве случаев я с этим согласен. Но при использовании Map я предпочитаю видеть полоску прогресса прямо над центром карты. Элемент управления Map обычно захватывает внимание пользователя, и по этой причине полоска прогресса в самом верху страницы может быть просто не замечена. Кроме того, полоска прогресса, показываемая на элементе управления Map сообщает пользователю, что работой занят именно этот элемент.

Связывание набора с данными

Связывание набора с элементом управления Map аналогично связыванию набора с ListBox, ListView, GridView или любым другим элементом управления, отображающим наборы. Чтобы проиллюстрировать это для Map, возьмем следующий класс:

public class Team
{
  public string TeamName { get; set; }
  public Uri ImageSource { get; set; }
  public string Division { get; set; }
  public string StadiumName { get; set; }
  public Geopoint StadiumLocation { get; set; }
  public Point NAP { get; set; }
}

Экземпляр этого класса можно было бы использовать для хранения базовой информации о профессиональной спортивной команде. Заметьте, что одно из свойств — Geopoint — содержит местоположение стадиона, используемого командой в качестве своего поля.

XAML на рис. 4 так настраивает элемент управления Map, чтобы с ним можно было связать набор объектов Team, а местоположение своего поля каждой команды отмечается маленьким значком.

Рис. 4. Настройка элемента управления Map для связывания с набором

<Maps:MapControl
  x:Name="myMapControl" Grid.Row="1"
  MapServiceToken="{StaticResource MapServiceTokenString}" >
  <Maps:MapItemsControl x:Name="MapItems" >
    <Maps:MapItemsControl.ItemTemplate>
      <DataTemplate>
        <Image Source="{Binding ImageSource}"
          Maps:MapControl.Location="{Binding StadiumLocation}"
          Maps:MapControl.NormalizedAnchorPoint="{Binding NAP}"
          Height="15" Width="15"
          />
      </DataTemplate>
    </Maps:MapItemsControl.ItemTemplate>
  </Maps:MapItemsControl>
</Maps:MapControl>

Если вы знакомы со связыванием наборов с другими элементами управления, то на рис. 4 для вас не должно быть ничего нового. Элемент управления Image содержится в DataTemplate. Подключаемое свойство Location элемента Image связывается со свойством StadiumLocation объекта Team. В элементе Image также есть подключаемое свойство NormalizedAnchorPoint, которое связывается со свойством, центрирующим изображение на местоположении стадиона.

Заметьте, что при связывании Map с набором, значение свойства NormalizedAnchorPoint нельзя «зашивать» в код. Оно должно быть связано со значением в нижележащем объекте. Если вы попытаетесь задать это свойство так:

Maps:MapControl.NormalizedAnchorPoint="0.5,0.5"

то XAML-редактору не понравится этот синтаксис, и значение никогда не будет присвоено. Microsoft известно об этой проблеме.

На рис. 5 представлен элемент управления Map, отображающий местоположения стадионов NFL. (Этот экранный снимок взят из примера кода, сопутствующего этой статье. В примере содержится весь вспомогательный код, не показанный здесь ради экономии места, например код, создающий экземпляр набора и должным образом форматирующий элемент управления, чтобы он корректно помещался на странице.))

Стадионы Национальной футбольной лиги (NFL)
Рис. 5. Стадионы Национальной футбольной лиги (NFL)

Масштабирование элементов управления

Элементы управления можно масштабировать, чтобы они представляли указанное расстояние. Например, вы хотите показать масштаб своей карты. Масштаб дает визуальную подсказку, позволяющую догадаться о расстояниях между объектами на карте. Кроме того, если вы используете Map для обозначения геозоны (geofence), хороший способ сделать это — добавить эллипс в элемент управления Map, придать ему форму окружности и изменить размер окружности так, чтобы она покрывала расстояние оповещения о геозоне (alert distance).

Элементы управления в Windows Phone 8.1 масштабируются заданием их ширины и высоты в пикселях. Поэтому такое масштабирование элементов управления, чтобы оно отражало некое расстояние, требует, в том числе, определить, какое расстояние представляется одним пикселем в элементе управления Map. Вот уравнение для определения расстояния, представляемого одним пикселем в Map:

const double BING_MAP_CONSTANT = 156543.04;
double MetersPerPixel =
  BING_MAP_CONSTANT * Math.Cos(latitude) / Math.Pow(2, zoomLevel);

Используемую широту (latitude) следует брать из свойства center элемента управления Map. Она должна быть в радианах, а не в градусах. Поскольку широта обычно выражается в градусах, вы должны преобразование ее значение в радианы, умножив значение в градусах на Pi/180 (Math.PI/180). Уровень масштабирования берется из одноименного параметра элемента управления Map и представляет собой значение от 1 до 20. В Windows Phone 8.1 это значение выражается типом double.

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

На первый взгляд уравнение может показаться неправильным. При чем тут широта? Разве масштаб карты не является простой функцией уровня масштабирования? Истина в том, что широта важна и что один уровень масштабирования недостаточен при определении масштаба карты. Bing Maps, который является серверным сервисом элемента управления Map, использует проекцию Меркатора (Mercator projection). Это метод проецирования деталей поверхности сферы (в данном случае земного шара) на плоскую поверхность. Эта проекция вносит несоответствия в масштаб, так как чем дальше вы отстоите от экватора, тем большее растяжение требуется для сохранения пропорций. Простой эксперимент поможет вам лучше понять проекцию Меркатора. Очистите апельсин и сохраните все кусочки кожуры. Полностью очистив апельсин, сложите кусочки кожуры вместе на плоской поверхности и попробуйте добиться того, чтобы они точно уложились в форму квадрата. Это невозможно. Единственный способ уложить эти кусочки в квадратную форму — растянуть те кусочки, которые не находятся на «экваторе» вашего апельсина. Чем ближе вы к «полюсам», тем больше нужно растягивать эти кусочки. Такое растягивание создает разницу в масштабе по сравнению с местоположениями, близкими к экватору. Величина необходимого растягивания является функцией расстояния от экватора. Отсюда и возникает зависимость от широты. В качестве примера такого растяжения в действии на проекции Меркатора применительно к Земле возьмите два города: Квебек (Канада) и Ки-Уэст (Флорида). Полностью приближенное представление (Zoom Level равен 20) Квебека при использовании элемента управления Map даст следующий результат: 100 пикселей соответствуют 33,5 футам. Тот же уровень масштабирования Ки-Уэста приводит к тому, что 100 пикселей соответствуют 44,5 футам. Жители Квебека наслаждаются масштабом на 11 футов лучше, чем у жителей Ки-Уэст — слабое утешение за более холодный климат. Подробнее о проекции Меркатора прочитайте статью «Understanding Scale and Resolution» в MSDN Library по ссылке bit.ly/1xIqEwC.

И последнее, на что следует обратить внимание, — Bing Map Constant. Эта константа основана на радиусе Земли и уравнениях, с помощью которых Microsoft определяет представление карты для заданного уровня масштаба. Она измеряется в метрах на пиксель.

На рис. 6 показаны TextBlock и Rectangle, добавленные в Map для использования в качестве шкалы расстояний. На рис. 7 приведен код обработчика события ZoomLevelChanged и логика, необходимая для создания шкалы расстояний. (В примере кода проверяется свойство RegionInfo.CurrentRegion.IsMetric и отображаются метрические значения для пользователей, которые более привычна метрическая система мер.) Наконец, на рис. 8 показан экранный снимок из примера кода: шкала расстояний, добавленная в элемент управления Map.

Рис. 6. XAML-элементы TextBlock и Rectangle, используемые в качестве шкалы расстояний

<Maps:MapControl
  x:Name="myMapControl" Grid.Row="1"
  MapServiceToken="{StaticResource MapServiceTokenString}"
  ZoomLevelChanged="myMapControl_ZoomLevelChanged">
  <!-- Шкала расстояний располагается
       в нижней левой части карты -->
  <TextBlock Name="tbScale" Text="Scale Text" FontSize="15" Foreground="Black"
    Margin="24,530,24,6" Opacity="0.6" />
  <Rectangle Name="recScale" Fill="Purple" Width="100" Height="6"
    Margin="24,548,24,24" Opacity="0.6" />
</Maps:MapControl>

Рис. 7. Обработчик события ZoomLevelChanged

private void myMapControl_ZoomLevelChanged(MapControl sender, object args)
{
  // Получаем текущий уровень масштаба
  // в элементе управления Map
  double zoomLevel = sender.ZoomLevel;
  // Используем широту из центральной точки Map
  double latitude = sender.Center.Position.Latitude;
  // Следующая формула для разрешения карты
  // требует широту в радианах
  latitude = latitude * (Math.PI / 180);
  // Эта константа основана на диаметре Земли и уравнениях,
  // с помощью которых Microsoft определяет карту, показываемую
  // для уровня масштаба в элементе управления Map
  const double BING_MAP_CONSTANT = 156543.04;
  // Вычисляем количество метров, представляемых одним пикселем
  double MetersPerPixel =
    BING_MAP_CONSTANT * Math.Cos(latitude) / Math.Pow(2, zoomLevel);
  // Дополнительные единицы
  double KilometersPerPixel = MetersPerPixel / 1000;
  double FeetPerPixel = MetersPerPixel * 3.28;
  double MilesPerPixel = FeetPerPixel / 5280;
  // Определяем расстояние, представленное
  // элементом управления Rectangle
  double scaleDistance = recScale.Width * MilesPerPixel;
  tbScale.Text = scaleDistance.ToString() + " miles";
}

Шкала расстояний, добавленная в Map и показывающая Sunset Pier в Ки-Уэсте (Флорида)
Рис. 8. Шкала расстояний, добавленная в Map и показывающая Sunset Pier в Ки-Уэсте (Флорида)

Загрузка карт для автономного использования

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

Карты нельзя скачать программным способом без согласия пользователя, так как они занимают большой объем. Пользователь должен давать согласие на каждое скачивание через системный UI, который позволяет отбирать нужные карты и скачивать их. Это выполняется статическим классом MapManager, который принадлежит пространству имен Windows.Services.Maps. Этот класс предоставляет функции как для скачивания карт, так и для их обновления. Функция ShowDownloadedMapsUI, показанная ниже, запустит встроенное приложение Maps и отобразит страницу, показанную на рис. 9:

MapManager.ShowDownloadedMapsUI();

UI для скачивания карт
Рис. 9. UI для скачивания карт

Встроенное приложение Maps и страница, показанная на рис. 9, также доступны касанием кнопки Download maps в меню Settings. Поскольку эта функция переключает пользователя на другое приложение (Maps), ему придется вручную возвращаться в исходное приложение.

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

Касание кнопки добавления (+) запускает мастер выбора карты, отображающего страницу, где можно указать континент, содержащий карту, которую вы хотите скачать. После выбора континента отображается страница, отображающая все страны на выбранном континенте. Вы можете выбрать все страны на континенте и скачать карты для всего континента, но это потребует большого объема хранилища. Например, все карты для США занимают 3,4 Гб в хранилище. А весь континент с Северной и Центральной Америкой займет намного больше места.

Если вы выбираете большую страну со множеством регионов или штатов, вы увидите страницу, позволяющую выбрать конкретные регионы или штаты. Используя кнопку Select, можно выбрать более одного региона. Указав регион, вы перейдете на страницу Download (рис. 10). Та же страница будет показана, если вы выберете небольшую страну безо всяких регионов или штатов.

Скачивание карты
Рис. 10. Скачивание карты

Перед скачиванием любой карты стоит предложить пользователю проверить доступное место на устройстве, перейдя в меню Settings приложения и выбрав Storage sense. Тогда будет отображено доступное место на устройстве, а также объемы хранилища, используемые каждым приложением на устройстве, на случай, если понадобится освободить место. На момент написания этой статьи никакого WinRT API, который позволил бы программно определить объем занятого на устройстве (или свободного) хранилища, не было.

Также неплохо скачивать карты при наличии соединения с неограниченной сетью, такой как Wi-Fi. В примере кода для этой статьи показано, как проверить текущее сетевое соединение и предупредить пользователя, если это тарифицируемое соединение.

Обновление загруженных карт

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

MapManager.ShowMapsUpdateUI();

Эта функция похожа на функцию ShowDownloadedMapsUI в том плане, что она переключает пользователя на встроенное приложение Maps. Когда эта функция вызывается, все загруженные карты проверяются, чтобы выяснить, нуждаются ли они в обновлении. Если какая-либо из ранее загруженных карт требует обновления, пользователю сообщается размер обновления и предоставляется возможность либо отменить обновление, либо продолжить его. Та же функциональность доступна и из меню Settings приложения Maps.

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

Заключение

В этой статье я показал, как добавить данные приложения в элемент управления Map для Windows Phone 8.1. Этот процесс включает добавление XAML-элементов на карту, связывание с данными и рисование элементов управления для масштабирования. Я также продемонстрировал, как сделать нижележащие данные элемента управления Map автономными, чтобы Map можно было настроить на бесшовную работу в приложениях, рассчитанных на автономное использование.


Кит Пижиновски (Keith Pijanowski) имеет более чем 20-летний опыт работы в индустрии ПО. Работал в начинающих и крупных компаниях на самых разных должностях и занимался всем — от написания кода до развития бизнеса. В настоящее время работает на себя как независимый консультант. Живет в центральной части Нью-Йорка. С ним можно связаться по адресу keithpij@msn.com ли через twitter.com/keithpij.

Выражаю благодарность за рецензирование статьи эксперту Microsoft Майку О'Мэлли (Mike O’Malley).