Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Windows App SDK и WinUI 3 предоставляют API и элементы управления для отображения карт, обнаружения расположения пользователя и настройки геозон. Используйте эти возможности для создания приложений, которые отображают интерактивные карты с метками, отслеживают местоположение пользователя и запускают действия, когда пользователь входит в географическую область или покидает её.
В этой статье приведены все возможности и полный пример, который объединяет MapControlи GeolocatorGeofenceMonitor в одном рабочем приложении.
Отображение карт с помощью MapControl
MapControl отображает интерактивную карту на базе Azure Maps. Вы можете добавлять метки, слои и реагировать на действия пользователя, такие как перемещение карты, масштабирование и щелчок мышью.
Для MapControl требуется учетная запись Azure Maps. См. статью "Управление учетной записью Azure Maps", чтобы создать учетную запись и получить маркер службы.
Подробные инструкции по использованию см. в разделе MapControl.
<MapControl x:Name="myMap"
MapServiceToken="YOUR_AZURE_MAPS_TOKEN"
Height="400" />
Note
API UWP MapControl и API Windows.Services.Maps устарели и могут быть недоступны в будущих версиях Windows. Приложения WinUI 3 должны использовать новый MapControl, описанный выше. Дополнительные сведения см. в разделе Ресурсы для устаревших функций.
Обнаружение расположения пользователя
API Windows.Devices.Geolocation позволяют определить географическое местоположение устройства. Эти API работают как в приложениях UWP, так и в Windows App SDK (WinUI 3). Можно сделать следующее:
- Получите одноразовое местоположение с помощью Geolocator.GetGeopositionAsync.
- Отслеживайте изменения положения с течением времени с помощью события Geolocator.PositionChanged .
- Отслеживайте изменения статуса посещения с помощью GeovisitMonitor для энергоэффективного определения местоположения.
Пошаговое руководство см. в разделе "Получение расположения пользователя".
Настройте геозоны
Геозона определяет географическую границу. Приложение получает уведомления при входе или выходе из границы. Геозоны используются для напоминаний с учётом местоположения, оповещений или предоставления контента.
Инструкции по созданию и мониторингу геозон см. в разделе "Настройка геозоны".
Возможности расположения и конфиденциальность
Для всех API расположений требуется возможность расположения , объявленная в манифесте пакета приложения. Перед доступом к данным расположения необходимо также вызвать Geolocator.RequestAccessAsync во время выполнения.
Windows предоставляет пользователям контроль над тем, какие приложения могут получить доступ к их расположению с помощью параметров > конфиденциальности и безопасности>. Приложение должно обрабатывать случай, когда пользователь запрещает доступ к местоположению или отзывает разрешение на него.
Полный пример
В следующем примере объединяются MapControlи GeolocatorGeofenceMonitor в одном окне WinUI 3. Если ключ Azure Maps не настроен, карта продолжает отображаться с ограниченной функциональностью, при этом геолокация и геозонирование продолжают работать.
Необходимые условия
- Windows App SDK 2.2 или более поздней версии
- Ключ Azure Maps , необходимый для отображения плиток карты. Без допустимого ключа объект MapControl отображает пустую карту.
- Возможность устройства Местоположение, объявленная в
Package.appxmanifest:
<DeviceCapability Name="location" />
Задайте ключ Azure Maps в качестве переменной среды перед запуском приложения:
$env:AZURE_MAPS_KEY = "your-key-here"
MainWindow.xaml
Слева — панель управления шириной 300 пикселей с кнопками и текстом состояния, а справа — MapControl. При отсутствии ключа Azure Maps появляется наложенный экран.
<?xml version="1.0" encoding="utf-8" ?>
<Window
x:Class="MapLocationDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Map Location Demo">
<Window.SystemBackdrop>
<MicaBackdrop />
</Window.SystemBackdrop>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TitleBar Title="Map Location Demo" />
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Margin="16" RowSpacing="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="Location Demo" FontSize="20" FontWeight="Bold"/>
<StackPanel Grid.Row="1" Spacing="8">
<Button x:Name="FindMeButton" Content="Find My Location"
Click="FindMeButton_Click" HorizontalAlignment="Stretch"/>
<Button x:Name="AddGeofenceButton" Content="Add Geofence Here"
Click="AddGeofenceButton_Click" HorizontalAlignment="Stretch"/>
</StackPanel>
<TextBlock x:Name="StatusText" Grid.Row="2"
Text="Click 'Find My Location' to begin." TextWrapping="Wrap"/>
<ListView x:Name="EventLog" Grid.Row="3" Header="Event Log"/>
</Grid>
<Grid Grid.Column="1">
<MapControl x:Name="MyMap" />
<StackPanel x:Name="MapKeyMissing" Visibility="Collapsed"
HorizontalAlignment="Center" VerticalAlignment="Center"
Spacing="8">
<FontIcon Glyph="" FontSize="48"
HorizontalAlignment="Center"
Foreground="{ThemeResource SystemFillColorCautionBrush}" />
<TextBlock Text="Azure Maps key not configured"
FontSize="18" FontWeight="SemiBold"
HorizontalAlignment="Center" />
<TextBlock x:Name="MapKeyHint" TextWrapping="Wrap" MaxWidth="400"
HorizontalAlignment="Center" TextAlignment="Center"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
</StackPanel>
</Grid>
</Grid>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Windows.Devices.Geolocation;
using Windows.Devices.Geolocation.Geofencing;
namespace MapLocationDemo;
public sealed partial class MainWindow : Window
{
private Geolocator? _geolocator;
private BasicGeoposition _lastPosition;
private bool _mapAvailable;
public MainWindow()
{
InitializeComponent();
_mapAvailable = TryConfigureMap();
GeofenceMonitor.Current.GeofenceStateChanged += OnGeofenceStateChanged;
}
// Read the Azure Maps key from an environment variable.
// If missing, collapse the map and show an informational overlay.
private bool TryConfigureMap()
{
var key = Environment.GetEnvironmentVariable("AZURE_MAPS_KEY");
if (string.IsNullOrWhiteSpace(key))
{
MyMap.Visibility = Visibility.Collapsed;
MapKeyMissing.Visibility = Visibility.Visible;
MapKeyHint.Text = "Set the AZURE_MAPS_KEY environment variable "
+ "and restart.\nGeolocation and geofencing still work "
+ "without the map.";
Log("Azure Maps key not found — map disabled");
return false;
}
MyMap.MapServiceToken = key;
return true;
}
private async void FindMeButton_Click(object sender, RoutedEventArgs e)
{
FindMeButton.IsEnabled = false;
StatusText.Text = "Requesting location access...";
var access = await Geolocator.RequestAccessAsync();
if (access != GeolocationAccessStatus.Allowed)
{
StatusText.Text =
"Location access denied. Check Settings > Privacy > Location.";
FindMeButton.IsEnabled = true;
return;
}
_geolocator = new Geolocator { DesiredAccuracyInMeters = 100 };
try
{
var pos = await _geolocator.GetGeopositionAsync();
var lat = pos.Coordinate.Point.Position.Latitude;
var lon = pos.Coordinate.Point.Position.Longitude;
_lastPosition = new BasicGeoposition
{
Latitude = lat, Longitude = lon
};
StatusText.Text =
$"Location: {lat:F5}, {lon:F5} ({pos.Coordinate.Accuracy:F0} m)";
Log($"Position: {lat:F5}, {lon:F5}");
if (_mapAvailable)
{
var pt = new Geopoint(_lastPosition);
MyMap.Center = pt;
MyMap.ZoomLevel = 15;
var layer = new MapElementsLayer();
layer.MapElements = new List<MapElement>
{
new MapIcon { Location = pt }
};
MyMap.Layers.Clear();
MyMap.Layers.Add(layer);
}
}
catch (Exception ex) { StatusText.Text = $"Error: {ex.Message}"; }
finally { FindMeButton.IsEnabled = true; }
}
private void AddGeofenceButton_Click(object sender, RoutedEventArgs e)
{
if (_lastPosition.Latitude == 0 && _lastPosition.Longitude == 0)
{
StatusText.Text = "Get your location first.";
return;
}
var fence = new Geofence("MyGeofence",
new Geocircle(_lastPosition, 200),
MonitoredGeofenceStates.Entered | MonitoredGeofenceStates.Exited,
false, TimeSpan.FromSeconds(5));
GeofenceMonitor.Current.Geofences.Add(fence);
StatusText.Text = $"Geofence added at "
+ $"{_lastPosition.Latitude:F5}, {_lastPosition.Longitude:F5}";
Log("Geofence registered");
}
private void OnGeofenceStateChanged(
GeofenceMonitor sender, object args)
{
var reports = sender.ReadReports();
DispatcherQueue.TryEnqueue(() =>
{
foreach (var r in reports)
{
var msg = r.NewState switch
{
GeofenceState.Entered => $"Entered: {r.Geofence.Id}",
GeofenceState.Exited => $"Exited: {r.Geofence.Id}",
GeofenceState.Removed => $"Removed: {r.Geofence.Id}",
_ => null
};
if (msg != null) { StatusText.Text = msg; Log(msg); }
}
});
}
private void Log(string msg) =>
EventLog.Items.Insert(0, $"[{DateTime.Now:HH:mm:ss}] {msg}");
}
Основные шаблоны
-
MapControlвстроен в Windows App SDK 1.6 и более поздних версий. ЗадайтеMapServiceTokenдля ключа Azure Maps. -
TryConfigureMapAZURE_MAPS_KEYпроверяет переменную среды при запуске. Если переменная пуста, карта сворачивается, а поверх нее появляется оверлей с пояснением, как это исправить, — никакого сбоя и никакой пустой карты. - Требуется
DeviceCapability Name="location"вPackage.appxmanifest, илиGeolocator.RequestAccessAsyncвозвращаетDenied. -
GeofenceMonitor.GeofenceStateChangedзапускается в фоновом потоке, поэтому используетсяDispatcherQueue.TryEnqueueдля обновления пользовательского интерфейса.
Связанные статьи
Windows developer