共用方式為


在地圖上重疊顯示並排影像

重要

針對企業用 Bing 地圖服務淘汰

UWP MapControlWindows.Services.Maps 命名空間的地圖服務都是依賴 Bing 地圖服務。 針對企業用 Bing 地圖服務已遭到取代且即將淘汰,屆時 MapControl 及服務將不再接收資料。

如需詳細資訊,請參閱 Bing 地圖服務開發人員中心Bing 地圖服務文件

注意

MapControl 和地圖服務要求地圖驗證金鑰,稱為 MapServiceToken。 如需取得和設定地圖驗證金鑰的詳細資訊,請參閱要求地圖驗證金鑰

使用磚來源,即可在地圖上重疊顯示協力廠商或自訂的並排影像。 您可以使用磚來源來重疊顯示專業資訊,例如氣象資料、人口資料或地震資料,或是使用磚來源完全取代預設的地圖。

圖格影像概觀

Bing 地圖服務等地圖服務會將地圖切成方形圖格,以便快速擷取和顯示。 這些圖格的大小為 256 x 256 像素,並以多個詳細程度預先轉譯。 許多第三方服務也提供切割成圖格的地圖資料。 使用圖格來源來擷取第三方圖格,或者建立您的自訂圖格,並重疊在 MapControl 顯示的地圖上。

當您使用磚來源時,不需要撰寫程式代碼來要求或放置個別磚。 MapControl 會要求圖格,因為它需要圖格。 每個要求都會指定個別圖格的 X 和 Y 座標和縮放等級。 您只需指定要用來擷取 UriFormatString 屬性中圖格的 Uri 或檔名格式。 也就是說,您會在基底 URI 或檔名中插入可取代的參數,以指出傳遞 X 和 Y 座標的位置,以及每個圖格的縮放等級。

以下是 HttpMapTileDataSourceUriFormatString 屬性範例,其中顯示 X 和 Y 座標和縮放等級的可取代參數。

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

X 與 Y 座標表示在指定詳細程度的世界地圖中,各個圖格的位置。圖格編號系統從地圖的左上角 {0, 0} 開始。例如,位於 {1, 2} 的圖格在網格的第三列第二行。

如需對應服務所使用圖格系統的詳細資訊,請參閱 Bing 地圖圖格系統

從圖格來源重疊圖格

使用 MapTileDataSource 重疊地圖圖格來源的圖格影像。

  1. 將繼承自 MapTileDataSource 的三個圖格資料來源類別之一具現化。

    UriFormatString 設定為要使用的格式,以便在基本 Uri 或檔案名稱中插入可替換的參數以要求圖格。

    下列範例會具現化 HttpMapTileDataSource。 此範例會在 HttpMapTileDataSource 的建構函式中指定 UriFormatString 的值。

        HttpMapTileDataSource dataSource = new HttpMapTileDataSource(
          "http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}");
    
  2. 具現化並設定 MapTileSource。 指定您在上一個步驟中設定為 MapTileSourceDataSourceMapTileDataSource

    下列範例會在 MapTileSource 的建構函式中指定 DataSource

        MapTileSource tileSource = new MapTileSource(dataSource);
    

    您可以使用 MapTileSource 的屬性來限制顯示圖格的條件。

    • 藉由提供 Bounds 屬性的值,只顯示特定地理區域內的圖格。
    • 只藉由提供 ZoomLevelRange 屬性的值,以特定詳細程度顯示圖格。

    或者,設定 MapTileSource 的其他屬性,以影響載入或顯示圖格,例如 LayerAllowOverstretchIsRetryEnabledIsTransparencyEnabled

  3. MapTileSource 新增至 MapControlTileSources 集合。

         MapControl1.TileSources.Add(tileSource);
    

從 Web 服務重疊圖格

使用 HttpMapTileDataSource 從 Web 服務擷取的重疊圖格影像。

  1. 具現化 HttpMapTileDataSource

  2. 指定 Web 服務預期為 UriFormatString 屬性值的 URI 格式。 若要建立此值,請在基底 URI 中插入可取代的參數。 例如,在下列程式碼範例中,UriFormatString 的值是:

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

    Web 服務必須支援 URI,其中包含可取代的參數 {x}、{y}和 {zoomlevel}。 大部分的 Web 服務 (例如 Nokia、Bing 和 Google) 都支援此格式的 URI。 如果 Web 服務需要 UriFormatString 屬性無法使用的其他引數,則必須建立自訂 URI。 藉由處理 UriRequested 事件來建立及傳回自訂 URI。 有關詳細資訊,請參閱本主題後面的「提供自訂 URI」一節。

  3. 然後,遵循先前在圖格影像概觀中所述的其餘步驟。

下列範例會在北美洲地圖上重疊虛構 Web 服務圖格。 UriFormatString 的值是在 HttpMapTileDataSource 的建構函式中指定。 在此範例中,圖格只會顯示在選擇性 Bounds 屬性所指定的地理界限內。

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

從本機儲存裝置重疊圖格

使用 LocalMapTileDataSource,重疊儲存在本機的圖格影像檔案。 一般而言,您會將這些檔案隨著應用程式封裝和散發。

  1. 具現化 LocalMapTileDataSource

  2. 將檔名的格式指定為 UriFormatString 屬性的值。 若要建立此值,請在基底檔名中插入可取代的參數。 例如,在下列程式碼範例中,UriFormatString 的值是:

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

    如果檔名格式需要 UriFormatString 屬性無法使用的其他引數,則必須建立自訂 URI。 藉由處理 UriRequested 事件來建立及傳回自訂 URI。 有關詳細資訊,請參閱本主題後面的「提供自訂 URI」一節。

  3. 然後,遵循先前在圖格影像概觀中所述的其餘步驟。

您可以使用下列通訊協定和位置,從本機儲存裝置載入圖格:

URI 其他資訊
ms-appx:/// 指向應用程式安裝資料夾的根目錄。
這是 Package.InstalledLocation 屬性所參考的位置。
ms-appdata:///local 指向應用程式本機儲存裝置的根目錄。
這是 ApplicationData.LocalFolder 屬性所參考的位置。
ms-appdata:///temp 指向應用程式的暫存資料夾。
這是 ApplicationData.TemporaryFolder 屬性所參考的位置。

下列範例會使用 ms-appx:/// 通訊協定載入儲存為應用程式安裝資料夾中檔案的圖格。 UriFormatString 的值是在 LocalMapTileDataSource 的建構函式中指定。 在此範例中,只有在地圖的縮放等級位於選用 ZoomLevelRange 屬性所指定的範圍內時,才會顯示圖格。

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

提供自訂 URI

如果 HttpMapTileDataSourceUriFormatString 屬性或 LocalMapTileDataSourceUriFormatString 屬性可用的可取代參數不足以擷取圖格,則您必須建立自訂 URI。 藉由提供 UriRequested 事件的自訂處理常式,建立及傳回自訂 URI。 每個個別圖格都會引發 UriRequested 事件。

  1. UriRequested 事件的自訂處理常式中,結合必要的自訂引數與 MapTileUriRequestedEventArgsXYZoomLevel 屬性,以建立自訂 Uri。
  2. 傳回 MapTileUriRequest Uri 屬性中的自訂 URI,該屬性包含在 MapTileUriRequestedEventArgsRequest 屬性中。

下列範例示範如何建立 UriRequested 事件的自訂處理常式來提供自訂 URI。 如果您必須以非同步方式執行某些動作來建立自訂 URI,它也會示範如何實作延遲模式。

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.        }
        }

從自訂來源重疊圖格

使用 CustomMapTileDataSource 重疊自訂圖格。 即時以程式設計方式在記憶體中建立圖格,或撰寫您自己的程序碼,以從另一個來源載入現有的圖格。

若要建立或載入自訂圖格,請提供 BitmapRequested 事件的自訂處理常式。 每個個別圖格都會引發 BitmapRequested 事件。

  1. BitmapRequested 事件的自訂處理常式中,結合必要的自訂引數與 MapTileBitmapRequestedEventArgsXYZoomLevel 屬性,以建立或擷取自訂圖格。
  2. 傳回 MapTileBitmapRequestPixelData 屬性中的自訂圖格,該屬性包含在 MapTileBitmapRequestedEventArgsRequest 屬性中。 PixelData 屬性的類型為 IRandomAccessStreamReference

下列範例示範如何建立 BitmapRequested 事件的自訂處理常式來提供自訂圖格。 此範例會建立部分不透明的相同紅色圖格。 此範例會忽略 MapTileBitmapRequestedEventArgsXYZoomLevel 屬性。 雖然這不是真實世界的範例,但此範例示範如何即時建立記憶體內部自訂圖格。 如果您必須以非同步方式執行某些動作來建立自訂圖格,此範例也會示範如何實作延遲模式。

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;
}

取代預設地圖

若要將預設地圖完全取代為第三方或自訂圖格: