Überlagern von nebeneinander angeordneten Bildern in einer Karte

Wichtig

Einstellung des Bing Maps for Enterprise-Diensts

Die UWP-MapControl- und Kartendienste aus dem Windows.Services.Maps-Namespace basieren auf Bing Maps. Bing Maps for Enterprise ist veraltet und wird eingestellt, zu diesem Zeitpunkt empfangen mapControl und Dienste keine Daten mehr.

Weitere Informationen finden Sie in der Bing Maps Developer Center - und Bing Maps-Dokumentation.

Hinweis

MapControl und Kartendienste erfordern einen Kartenauthentifizierungsschlüssel namens MapServiceToken. Weitere Informationen zum Abrufen und Festlegen eines Kartenauthentifizierungsschlüssels finden Sie unter Anfordern eines Kartenauthentifizierungsschlüssels.

Überlagern Sie Bilder von Drittanbietern oder benutzerdefinierte nebeneinander angeordnete Bilder in einer Karte mithilfe von Kachelquellen. Verwenden Sie Kachelquellen, um spezielle Infos wie Wetterdaten, Einwohnerzahlen oder seismische Daten zu überlagern oder die Standardkarte vollständig zu ersetzen.

Übersicht über nebeneinander angeordnete Bilder

Kartendienste wie Bing Maps schneiden Karten in quadratische Kacheln aus, um schnelles Abrufen und Anzeigen zu ermöglichen. Diese Kacheln sind 256 Pixel mal 256 Pixel groß und werden auf mehreren Detailebenen vorab gerendert. Viele Drittanbieterdienste stellen auch kartenbasierte Daten bereit, die in Kacheln aufgeteilt werden. Verwenden Sie Kachelquellen, um Kacheln von Drittanbietern abzurufen oder eigene benutzerdefinierte Kacheln zu erstellen und auf der Karte zu überlagern, die in MapControl angezeigt wird.

Wenn Sie Kachelquellen verwenden, müssen Sie keinen Code schreiben, um einzelne Kacheln anzufordern oder zu positionieren. Die MapControl fordert Kacheln an, wie sie benötigt werden. Jede Anforderung gibt die X- und Y-Koordinaten und den Zoomfaktor für die einzelne Kachel an. Sie geben einfach das Format des URI oder Dateinamens an, das zum Abrufen der Kacheln in der UriFormatString-Eigenschaft verwendet werden soll. Das heißt, Sie fügen ersetzbare Parameter in den Basis-URI oder Dateinamen ein, um anzugeben, wo die X- und Y-Koordinaten und der Zoomfaktor für jede Kachel übergeben werden sollen.

Hier ist ein Beispiel für die UriFormatString-Eigenschaft für eine HttpMapTileDataSource , die die ersetzbaren Parameter für die X- und Y-Koordinaten und den Zoomfaktor anzeigt.

http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}

(Die X- und Y-Koordinaten stellen die Position der einzelnen Kachel innerhalb der Karte der Welt auf der angegebenen Detailebene dar. Das Kachelnummerierungssystem beginnt von {0, 0} in der oberen linken Ecke der Karte. Die Kachel bei {1, 2} befindet sich beispielsweise in der zweiten Spalte der dritten Zeile des Kachelrasters.)

Weitere Informationen zum Kachelsystem, das von Zuordnungsdiensten verwendet wird, finden Sie unter Bing Maps Tile System.

Überlagern von Kacheln aus einer Kachelquelle

Überlagern Sie nebeneinander angeordnete Bilder aus einer Kachelquelle auf einer Karte mithilfe der MapTileDataSource.

  1. Instanziieren Sie eine der drei Kacheldatenquellenklassen, die von MapTileDataSource erben.

    Konfigurieren Sie die UriFormatString so, dass sie zum Anfordern der Kacheln verwendet wird, indem Sie ersetzbare Parameter in den Basis-URI oder Dateinamen einfügen.

    Im folgenden Beispiel wird eine HttpMapTileDataSource instanziiert. In diesem Beispiel wird der Wert der UriFormatString im Konstruktor der HttpMapTileDataSource angegeben.

        HttpMapTileDataSource dataSource = new HttpMapTileDataSource(
          "http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}");
    
  2. Instanziieren und Konfigurieren einer MapTileSource. Geben Sie die MapTileDataSource an, die Sie im vorherigen Schritt als DataSource der MapTileSource konfiguriert haben.

    Im folgenden Beispiel wird die DataSource im Konstruktor der MapTileSource angegeben.

        MapTileSource tileSource = new MapTileSource(dataSource);
    

    Sie können die Bedingungen einschränken, unter denen die Kacheln mithilfe von Eigenschaften der MapTileSource angezeigt werden.

    • Zeigen Sie Kacheln nur innerhalb eines bestimmten geografischen Gebiets an, indem Sie einen Wert für die Bounds-Eigenschaft angeben.
    • Zeigen Sie Kacheln nur auf bestimmten Detailebenen an, indem Sie einen Wert für die ZoomLevelRange-Eigenschaft angeben.

    Konfigurieren Sie optional andere Eigenschaften der MapTileSource, die sich auf das Laden oder die Anzeige der Kacheln auswirken, z. B. Layer, AllowOverstretch, IsRetryEnabled und IsTransparencyEnabled.

  3. Fügen Sie die MapTileSource der TileSources-Auflistung von MapControl hinzu.

         MapControl1.TileSources.Add(tileSource);
    

Überlagern von Kacheln aus einem Webdienst

Überlagern Sie nebeneinander angeordnete Bilder, die von einem Webdienst mithilfe der HttpMapTileDataSource abgerufen wurden.

  1. Instanziieren Sie eine HttpMapTileDataSource.

  2. Geben Sie das Format des URI an, den der Webdienst als Wert der UriFormatString-Eigenschaft erwartet. Fügen Sie zum Erstellen dieses Werts ersetzbare Parameter in den Basis-URI ein. Im folgenden Codebeispiel lautet beispielsweise der Wert der UriFormatString :

    http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}
    

    Der Webdienst muss einen URI unterstützen, der die ersetzbaren Parameter {x}, {y} und {zoomlevel} enthält. Die meisten Webdienste (z. B. Nokia, Bing und Google) unterstützen URIs in diesem Format. Wenn der Webdienst zusätzliche Argumente erfordert, die nicht mit der UriFormatString-Eigenschaft verfügbar sind, müssen Sie einen benutzerdefinierten URI erstellen. Erstellen und zurückgeben Sie einen benutzerdefinierten URI, indem Sie das UriRequested-Ereignis behandeln. Weitere Informationen finden Sie im Abschnitt "Bereitstellen eines benutzerdefinierten URI " weiter unten in diesem Thema.

  3. Führen Sie dann die verbleibenden Schritte aus, die zuvor in der Übersicht über nebeneinander angeordnete Bilder beschrieben wurden.

Im folgenden Beispiel werden Kacheln aus einem fiktiven Webdienst auf einer Karte von Nordamerika überlagert. Der Wert der UriFormatString wird im Konstruktor der HttpMapTileDataSource angegeben. In diesem Beispiel werden Kacheln nur innerhalb der geografischen Grenzen angezeigt, die durch die optionale Bounds-Eigenschaft angegeben werden.

private void AddHttpMapTileSource()
{
    // Create the bounding box in which the tiles are displayed.
    // This example represents North America.
    BasicGeoposition northWestCorner =
        new BasicGeoposition() { Latitude = 48.38544, Longitude = -124.667360 };
    BasicGeoposition southEastCorner =
        new BasicGeoposition() { Latitude = 25.26954, Longitude = -80.30182 };
    GeoboundingBox boundingBox = new GeoboundingBox(northWestCorner, southEastCorner);

    // Create an HTTP data source.
    // This example retrieves tiles from a fictitious web service.
    HttpMapTileDataSource dataSource = new HttpMapTileDataSource(
        "http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}");

    // Optionally, add custom HTTP headers if the web service requires them.
    dataSource.AdditionalRequestHeaders.Add("header name", "header value");

    // Create a tile source and add it to the Map control.
    MapTileSource tileSource = new MapTileSource(dataSource);
    tileSource.Bounds = boundingBox;
    MapControl1.TileSources.Add(tileSource);
}
...
#include <winrt/Windows.Devices.Geolocation.h>
#include <winrt/Windows.UI.Xaml.Controls.Maps.h>
...
void MainPage::AddHttpMapTileSource()
{
    Windows::Devices::Geolocation::BasicGeoposition northWest{ 48.38544, -124.667360 };
    Windows::Devices::Geolocation::BasicGeoposition southEast{ 25.26954, -80.30182 };
    Windows::Devices::Geolocation::GeoboundingBox boundingBox{ northWest, southEast };

    Windows::UI::Xaml::Controls::Maps::HttpMapTileDataSource dataSource{
        L"http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}" };

    dataSource.AdditionalRequestHeaders().Insert(L"header name", L"header value");

    Windows::UI::Xaml::Controls::Maps::MapTileSource tileSource{ dataSource };
    tileSource.Bounds(boundingBox);

    MapControl1().TileSources().Append(tileSource);
}
...
void MainPage::AddHttpMapTileSource()
{
    BasicGeoposition northWest = { 48.38544, -124.667360 };
    BasicGeoposition southEast = { 25.26954, -80.30182 };
    GeoboundingBox^ boundingBox = ref new GeoboundingBox(northWest, southEast);

    auto dataSource = ref new Windows::UI::Xaml::Controls::Maps::HttpMapTileDataSource(
        "http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}");

    dataSource->AdditionalRequestHeaders->Insert("header name", "header value");

    auto tileSource = ref new Windows::UI::Xaml::Controls::Maps::MapTileSource(dataSource);
    tileSource->Bounds = boundingBox;

    this->MapControl1->TileSources->Append(tileSource);
}

Überlagern von Kacheln aus dem lokalen Speicher

Überlagern Sie nebeneinander angeordnete Bilder, die als Dateien im lokalen Speicher gespeichert sind, mithilfe der LocalMapTileDataSource. In der Regel packen und verteilen Sie diese Dateien mit Ihrer App.

  1. Instanziieren Sie eine LocalMapTileDataSource.

  2. Geben Sie das Format der Dateinamen als Wert der UriFormatString-Eigenschaft an. Fügen Sie zum Erstellen dieses Werts ersetzbare Parameter in den Basisdateinamen ein. Im folgenden Codebeispiel lautet beispielsweise der Wert der UriFormatString:

        Tile_{zoomlevel}_{x}_{y}.png
    

    Wenn das Format der Dateinamen zusätzliche Argumente erfordert, die nicht mit der UriFormatString-Eigenschaft verfügbar sind, müssen Sie einen benutzerdefinierten URI erstellen. Erstellen und zurückgeben Sie einen benutzerdefinierten URI, indem Sie das UriRequested-Ereignis behandeln. Weitere Informationen finden Sie im Abschnitt "Bereitstellen eines benutzerdefinierten URI " weiter unten in diesem Thema.

  3. Führen Sie dann die verbleibenden Schritte aus, die zuvor in der Übersicht über nebeneinander angeordnete Bilder beschrieben wurden.

Sie können die folgenden Protokolle und Speicherorte verwenden, um Kacheln aus dem lokalen Speicher zu laden:

URI Weitere Informationen
ms-appx:/// Verweist auf den Stamm des Installationsordners der App.
Dies ist der Speicherort, auf den von der Package.InstalledLocation-Eigenschaft verwiesen wird.
ms-appdata:///local Verweist auf den Stamm des lokalen Speichers der App.
Dies ist der Speicherort, auf den von der ApplicationData.LocalFolder-Eigenschaft verwiesen wird.
ms-appdata:///temp Verweist auf den temporären Ordner der App.
Dies ist der Speicherort, auf den von der ApplicationData.TemporaryFolder-Eigenschaft verwiesen wird.

Im folgenden Beispiel werden Kacheln geladen, die mithilfe des ms-appx:/// Protokolls als Dateien im Installationsordner der App gespeichert werden. Der Wert für UriFormatString wird im Konstruktor der LocalMapTileDataSource angegeben. In diesem Beispiel werden Kacheln nur angezeigt, wenn sich der Zoomfaktor der Karte innerhalb des bereichs befindet, der durch die optionale ZoomLevelRange-Eigenschaft angegeben wird.

void AddLocalMapTileSource()
{
    // Specify the range of zoom levels
    // at which the overlaid tiles are displayed.
    MapZoomLevelRange range;
    range.Min = 11;
    range.Max = 20;

    // Create a local data source.
    LocalMapTileDataSource dataSource = new LocalMapTileDataSource(
        "ms-appx:///TileSourceAssets/Tile_{zoomlevel}_{x}_{y}.png");

    // Create a tile source and add it to the Map control.
    MapTileSource tileSource = new MapTileSource(dataSource);
    tileSource.ZoomLevelRange = range;
    MapControl1.TileSources.Add(tileSource);
}

Bereitstellen eines benutzerdefinierten URI

Wenn die austauschbaren Parameter, die mit der UriFormatString-Eigenschaft der HttpMapTileDataSource oder der UriFormatString-Eigenschaft der LocalMapTileDataSource verfügbar sind, nicht ausreichen, um Ihre Kacheln abzurufen, müssen Sie einen benutzerdefinierten URI erstellen. Erstellen und zurückgeben Sie einen benutzerdefinierten URI, indem Sie einen benutzerdefinierten Handler für das UriRequested-Ereignis bereitstellen. Das UriRequested-Ereignis wird für jede einzelne Kachel ausgelöst.

  1. Kombinieren Sie in Ihrem benutzerdefinierten Handler für das UriRequested-Ereignis die erforderlichen benutzerdefinierten Argumente mit den Eigenschaften X, Y und ZoomLevel der MapTileUriRequestedEventArgs, um den benutzerdefinierten URI zu erstellen.
  2. Gibt den benutzerdefinierten URI in der URI-Eigenschaft der MapTileUriRequest zurück, die in der Request-Eigenschaft der MapTileUriRequestedEventArgs enthalten ist.

Das folgende Beispiel zeigt, wie Sie einen benutzerdefinierten URI bereitstellen, indem Sie einen benutzerdefinierten Handler für das UriRequested-Ereignis erstellen. Außerdem wird gezeigt, wie Sie das Verzögerungsmuster implementieren, wenn Sie asynchron etwas tun müssen, um den benutzerdefinierten URI zu erstellen.

using Windows.UI.Xaml.Controls.Maps;
using System.Threading.Tasks;
...
            var httpTileDataSource = new HttpMapTileDataSource();
            // Attach a handler for the UriRequested event.
            httpTileDataSource.UriRequested += HandleUriRequestAsync;
            MapTileSource httpTileSource = new MapTileSource(httpTileDataSource);
            MapControl1.TileSources.Add(httpTileSource);
...
        // Handle the UriRequested event.
        private async void HandleUriRequestAsync(HttpMapTileDataSource sender,
            MapTileUriRequestedEventArgs args)
        {
            // Get a deferral to do something asynchronously.
            // Omit this line if you don't have to do something asynchronously.
            var deferral = args.Request.GetDeferral();

            // Get the custom Uri.
            var uri = await GetCustomUriAsync(args.X, args.Y, args.ZoomLevel);

            // Specify the Uri in the Uri property of the MapTileUriRequest.
            args.Request.Uri = uri;

            // Notify the app that the custom Uri is ready.
            // Omit this line also if you don't have to do something asynchronously.
            deferral.Complete();
        }

        // Create the custom Uri.
        private async Task<Uri> GetCustomUriAsync(int x, int y, int zoomLevel)
        {
            // Do something asynchronously to create and return the custom Uri.        }
        }

Überlagern von Kacheln aus einer benutzerdefinierten Quelle

Überlagern Sie benutzerdefinierte Kacheln mithilfe der CustomMapTileDataSource. Erstellen Sie Kacheln programmgesteuert im Arbeitsspeicher, oder schreiben Sie Ihren eigenen Code, um vorhandene Kacheln aus einer anderen Quelle zu laden.

Um benutzerdefinierte Kacheln zu erstellen oder zu laden, stellen Sie einen benutzerdefinierten Handler für das BitmapRequested-Ereignis bereit. Das BitmapRequested-Ereignis wird für jede einzelne Kachel ausgelöst.

  1. Kombinieren Sie in Ihrem benutzerdefinierten Handler für das BitmapRequested-Ereignis die erforderlichen benutzerdefinierten Argumente mit den Eigenschaften X, Y und ZoomLevel der MapTileBitmapRequestedEventArgs, um eine benutzerdefinierte Kachel zu erstellen oder abzurufen.
  2. Gibt die benutzerdefinierte Kachel in der PixelData-Eigenschaft der MapTileBitmapRequest zurück, die in der Request-Eigenschaft der MapTileBitmapRequestedEventArgs enthalten ist. Die PixelData-Eigenschaft ist vom Typ "IRandomAccessStreamReference".

Das folgende Beispiel zeigt, wie Sie benutzerdefinierte Kacheln bereitstellen, indem Sie einen benutzerdefinierten Handler für das BitmapRequested-Ereignis erstellen. In diesem Beispiel werden identische rote Kacheln erstellt, die teilweise undurchsichtig sind. Im Beispiel werden die X-, Y- und ZoomLevel-Eigenschaften der MapTileBitmapRequestedEventArgs ignoriert. Obwohl dies kein echtes Beispiel ist, veranschaulicht das Beispiel, wie Sie benutzerdefinierte Kacheln im Arbeitsspeicher im Handformat erstellen können. Das Beispiel zeigt auch, wie Sie das Verzögerungsmuster implementieren, wenn Sie asynchron etwas tun müssen, um die benutzerdefinierten Kacheln zu erstellen.

using Windows.UI.Xaml.Controls.Maps;
using Windows.Storage.Streams;
using System.Threading.Tasks;
...
        CustomMapTileDataSource customDataSource = new CustomMapTileDataSource();
        // Attach a handler for the BitmapRequested event.
        customDataSource.BitmapRequested += customDataSource_BitmapRequestedAsync;
        customTileSource = new MapTileSource(customDataSource);
        MapControl1.TileSources.Add(customTileSource);
...
        // Handle the BitmapRequested event.
        private async void customDataSource_BitmapRequestedAsync(
            CustomMapTileDataSource sender,
            MapTileBitmapRequestedEventArgs args)
        {
            var deferral = args.Request.GetDeferral();
            args.Request.PixelData = await CreateBitmapAsStreamAsync();
            deferral.Complete();
        }

        // Create the custom tiles.
        // This example creates red tiles that are partially opaque.
        private async Task<RandomAccessStreamReference> CreateBitmapAsStreamAsync()
        {
            int pixelHeight = 256;
            int pixelWidth = 256;
            int bpp = 4;

            byte[] bytes = new byte[pixelHeight * pixelWidth * bpp];

            for (int y = 0; y < pixelHeight; y++)
            {
                for (int x = 0; x < pixelWidth; x++)
                {
                    int pixelIndex = y * pixelWidth + x;
                    int byteIndex = pixelIndex * bpp;

                    // Set the current pixel bytes.
                    bytes[byteIndex] = 0xff;        // Red
                    bytes[byteIndex + 1] = 0x00;    // Green
                    bytes[byteIndex + 2] = 0x00;    // Blue
                    bytes[byteIndex + 3] = 0x80;    // Alpha (0xff = fully opaque)
                }
            }

            // Create RandomAccessStream from byte array.
            InMemoryRandomAccessStream randomAccessStream =
                new InMemoryRandomAccessStream();
            IOutputStream outputStream = randomAccessStream.GetOutputStreamAt(0);
            DataWriter writer = new DataWriter(outputStream);
            writer.WriteBytes(bytes);
            await writer.StoreAsync();
            await writer.FlushAsync();
            return RandomAccessStreamReference.CreateFromStream(randomAccessStream);
        }
...
#include <winrt/Windows.Storage.Streams.h>
...
Windows::Foundation::IAsyncOperation<Windows::Storage::Streams::InMemoryRandomAccessStream> MainPage::CustomRandomAccessStream()
{
    constexpr int pixelHeight{ 256 };
    constexpr int pixelWidth{ 256 };
    constexpr int bpp{ 4 };

    std::array<uint8_t, pixelHeight * pixelWidth * bpp> bytes;

    for (int y = 0; y < pixelHeight; y++)
    {
        for (int x = 0; x < pixelWidth; x++)
        {
            int pixelIndex{ y * pixelWidth + x };
            int byteIndex{ pixelIndex * bpp };

            // Set the current pixel bytes.
            bytes[byteIndex] = (byte)(std::rand() % 256);        // Red
            bytes[byteIndex + 1] = (byte)(std::rand() % 256);    // Green
            bytes[byteIndex + 2] = (byte)(std::rand() % 256);    // Blue
            bytes[byteIndex + 3] = (byte)((std::rand() % 56) + 200);    // Alpha (0xff = fully opaque)
        }
    }

    // Create RandomAccessStream from byte array.
    Windows::Storage::Streams::InMemoryRandomAccessStream randomAccessStream;
    Windows::Storage::Streams::IOutputStream outputStream{ randomAccessStream.GetOutputStreamAt(0) };
    Windows::Storage::Streams::DataWriter writer{ outputStream };
    writer.WriteBytes(bytes);

    co_await writer.StoreAsync();
    co_await writer.FlushAsync();

    co_return randomAccessStream;
}
...
InMemoryRandomAccessStream^ TileSources::CustomRandomAccessStream::get()
{
    int pixelHeight = 256;
    int pixelWidth = 256;
    int bpp = 4;

    Array<byte>^ bytes = ref new Array<byte>(pixelHeight * pixelWidth * bpp);

    for (int y = 0; y < pixelHeight; y++)
    {
        for (int x = 0; x < pixelWidth; x++)
        {
            int pixelIndex = y * pixelWidth + x;
            int byteIndex = pixelIndex * bpp;

            // Set the current pixel bytes.
            bytes[byteIndex] = (byte)(std::rand() % 256);        // Red
            bytes[byteIndex + 1] = (byte)(std::rand() % 256);    // Green
            bytes[byteIndex + 2] = (byte)(std::rand() % 256);    // Blue
            bytes[byteIndex + 3] = (byte)((std::rand() % 56) + 200);    // Alpha (0xff = fully opaque)
        }
    }

    // Create RandomAccessStream from byte array.
    InMemoryRandomAccessStream^ randomAccessStream = ref new InMemoryRandomAccessStream();
    IOutputStream^ outputStream = randomAccessStream->GetOutputStreamAt(0);
    DataWriter^ writer = ref new DataWriter(outputStream);
    writer->WriteBytes(bytes);

    create_task(writer->StoreAsync()).then([writer](unsigned int)
    {
        create_task(writer->FlushAsync());
    });

    return randomAccessStream;
}

Ersetzen der Standardkarte

So ersetzen Sie die Standardzuordnung vollständig durch Drittanbieter- oder benutzerdefinierte Kacheln: