Gambaran umum peta dan lokasi

SDK Aplikasi Windows dan WinUI 3 menyediakan API dan kontrol untuk menampilkan peta, mendeteksi lokasi pengguna, dan menyiapkan geofence. Gunakan kemampuan ini untuk membuat aplikasi yang menampilkan peta interaktif dengan pin, melacak posisi pengguna, dan memicu tindakan saat pengguna memasuki atau meninggalkan area geografis.

Artikel ini memperkenalkan setiap kemampuan dan menyertakan contoh lengkap yang menggabungkan MapControl, , Geolocatordan GeofenceMonitor dalam satu aplikasi yang berfungsi.

Menampilkan peta dengan MapControl

MapControl menampilkan peta interaktif yang didukung oleh Azure Maps. Anda dapat menambahkan pin, lapisan, dan merespons interaksi pengguna seperti menggeser, memperbesar, dan mengklik.

MapControl memerlukan akun Azure Maps. Lihat Mengelola akun Azure Maps Anda untuk membuat akun dan mendapatkan token layanan.

Untuk petunjuk penggunaan terperinci, lihat MapControl.

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

Note

UWP MapControl dan Windows. API Services.Maps tidak digunakan lagi dan mungkin tidak tersedia dalam versi Windows mendatang. Aplikasi WinUI 3 harus menggunakan MapControl baru yang dijelaskan di atas. Untuk informasi selengkapnya, lihat Sumber Daya untuk fitur yang tidak digunakan lagi.

Mendeteksi lokasi pengguna

Windows. Devices.Geolocation API memungkinkan Anda mendapatkan posisi geografis perangkat. API ini berfungsi di aplikasi UWP dan SDK Aplikasi Windows (WinUI 3). Kamu bisa:

Untuk panduan langkah demi langkah, lihat Mendapatkan lokasi pengguna.

Siapkan geofence

Geofence mendefinisikan batas geografis. Aplikasi Anda menerima pemberitahuan saat pengguna memasuki atau keluar dari batas. Geofence berguna untuk pengingat, pemberitahuan, atau pengiriman konten berbasis lokasi.

Untuk petunjuk tentang membuat dan memantau geofence, lihat Menyiapkan geofence.

Kemampuan dan privasi lokasi

Semua API lokasi memerlukan kemampuan Lokasi yang dideklarasikan dalam manifes paket aplikasi Anda. Anda juga harus memanggil Geolocator.RequestAccessAsync pada runtime sebelum mengakses data lokasi.

Windows memberi pengguna kontrol atas aplikasi mana yang dapat mengakses lokasi mereka melalui Pengaturan Privasi & Lokasi keamanan. Aplikasi Anda harus menangani kasus di mana pengguna menolak atau mencabut akses lokasi.

Contoh lengkap

Contoh berikut menyatukan MapControl, Geolocator, dan GeofenceMonitor dalam satu jendela WinUI 3. Jika tidak ada kunci Azure Maps yang dikonfigurasi, peta diturunkan dengan anggun saat geolokasi dan geofencing terus berfungsi.

Prerequisites

  • SDK Aplikasi Windows 2.2 atau yang lebih baru
  • Kunci Azure Maps — diperlukan untuk menampilkan petak peta. Tanpa kunci yang valid, MapControl merender tetapi menampilkan peta kosong.
  • Kemampuan perangkat Lokasi dideklarasikan dalam Package.appxmanifest:
<DeviceCapability Name="location" />

Atur kunci Azure Maps Anda sebagai variabel lingkungan sebelum menjalankan aplikasi:

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

MainWindow.xaml

Panel kontrol 300 piksel di sebelah kiri dengan tombol dan teks status, dan MapControl di sebelah kanan. Overlay muncul saat kunci Azure Maps hilang.

<?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}");
}

Pola kunci

  • MapControl tersedia sebagai bagian dari SDK Aplikasi Windows 1.6 dan versi yang lebih baru. Atur MapServiceToken ke kunci Azure Maps Anda.
  • TryConfigureMap AZURE_MAPS_KEY memeriksa variabel lingkungan pada startup. Jika variabel tersebut kosong, peta akan menciut dan overlay akan menjelaskan cara memperbaikinya — tidak terjadi crash, dan tidak akan muncul peta kosong.
  • DeviceCapability Name="location" di dalam Package.appxmanifest diperlukan atau Geolocator.RequestAccessAsync mengembalikan Denied.
  • GeofenceMonitor.GeofenceStateChanged diaktifkan pada utas latar belakang, jadi gunakan DispatcherQueue.TryEnqueue untuk memperbarui UI.