Overzicht van kaarten en locaties

Windows App SDK en WinUI 3 bieden API's en besturingselementen voor het weergeven van kaarten, het detecteren van de locatie van de gebruiker en het instellen van geofences. Gebruik deze mogelijkheden om apps te bouwen die interactieve kaarten met spelden weergeven, de positie van de gebruiker bijhouden en acties activeren wanneer de gebruiker een geografisch gebied binnenkomt of verlaat.

In dit artikel maakt u kennis met elke mogelijkheid en bevat een volledig voorbeeld waarin , MapControlen Geolocator in één werkende app worden gecombineerdGeofenceMonitor.

Kaarten weergeven met MapControl

In MapControl wordt een interactieve kaart weergegeven die mogelijk wordt gemaakt door Azure Maps. U kunt markeringen en lagen toevoegen en reageren op gebruikersacties, zoals slepen, zoomen en klikken.

MapControl vereist een Azure Maps-account. Zie Uw Azure Maps-account beheren om een account te maken en een servicetoken te verkrijgen.

Zie MapControl voor gedetailleerde gebruiksinstructies.

<MapControl x:Name="myMap"
            MapServiceToken="YOUR_AZURE_MAPS_TOKEN"
            Height="400" />

Note

De UWP MapControl en Windows. Services.Maps-API's zijn afgeschaft en zijn mogelijk niet beschikbaar in toekomstige versies van Windows. WinUI 3-apps moeten gebruikmaken van de nieuwe MapControl die hierboven wordt beschreven. Zie Resources voor afgeschafte functies voor meer informatie.

De locatie van de gebruiker detecteren

Met de Windows.Devices.Geolocation-API's kunt u de geografische positie van het apparaat ophalen. Deze API's werken in zowel UWP- als Windows App SDK -apps (WinUI 3). U kunt:

Zie De locatie van de gebruiker ophalen voor een stapsgewijze handleiding.

Geofences instellen

Een Geofence definieert een geografische grens. Uw app ontvangt meldingen wanneer de gebruiker de grens binnenkomt of verlaat. Geofences zijn handig voor op locatie gebaseerde herinneringen, waarschuwingen of contentlevering.

Zie Een geofence instellen voor instructies voor het maken en bewaken van geofences.

Locatiemogelijkheden en privacy

Voor alle locatie-API's is de mogelijkheid Locatie vereist die is gedeclareerd in het pakketmanifest van uw app. U moet geolocator.RequestAccessAsync ook aanroepen tijdens runtime voordat u toegang krijgt tot locatiegegevens.

Windows geeft gebruikers controle over welke apps toegang hebben tot hun locatie via instellingen > privacy en beveiligingslocatie>. Uw app moet de situatie afhandelen waarin de gebruiker de toegang tot de locatie weigert of intrekt.

Volledig voorbeeld

In het volgende voorbeeld worden MapControl, Geolocator en GeofenceMonitor samengebracht in één WinUI 3-venster. Als er geen Azure Maps-sleutel is geconfigureerd, verslechtert de kaart probleemloos terwijl geolocatie en geofencing blijven werken.

Vereiste voorwaarden

  • Windows App SDK 2.2 of hoger
  • Een Azure Maps-sleutel: vereist voor het weergeven van kaarttegels. Zonder een geldige sleutel wordt MapControl wel weergegeven, maar toont het een lege kaart.
  • De locatie-apparaatmogelijkheid gedeclareerd in Package.appxmanifest:
<DeviceCapability Name="location" />

Stel uw Azure Maps-sleutel in als een omgevingsvariabele voordat u de app uitvoert:

$env:AZURE_MAPS_KEY = "your-key-here"

MainWindow.xaml

Een configuratiescherm van 300 pixels aan de linkerkant met knoppen en statustekst, en een MapControl aan de rechterkant. Er wordt een overlay weergegeven wanneer de Azure Maps sleutel ontbreekt.

<?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="&#xE783;" 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}");
}

Belangrijke patronen

  • MapControlis ingebouwd in Windows App SDK 1,6 en hoger. Stel MapServiceToken in op uw Azure Maps-sleutel.
  • TryConfigureMap controleert de AZURE_MAPS_KEY omgevingsvariabele bij het opstarten. Als de variabele leeg is, wordt de kaart samengevouwen en wordt in een overlay uitgelegd hoe u deze kunt oplossen: geen crash, geen lege kaart.
  • DeviceCapability Name="location" in Package.appxmanifest is vereist, anders retourneert Geolocator.RequestAccessAsyncDenied.
  • GeofenceMonitor.GeofenceStateChanged wordt uitgevoerd op een achtergrondthread, dus gebruik DispatcherQueue.TryEnqueue om de UI bij te werken.