Daizen Ikehara

インフラジスティックス・ジャパン株式会社の元デベロッパー エバンジェリスト、現製品担当の Blog
[Silverlight] xamMap で Bing SOAP Services を使う [WPF] [Tips]

前回のエントリで予告していたように今回は xamMapBing Maps SOAP Services を利用し、地図情報の表示、経緯度の取得までを行います。なお、セッションサンプルでは LightSwitch を利用していましたが、今回は xamMap の部分に注力するため、通常の Silverlight アプリケーションで作成しています。また、今回は全てイベント ハンドラーで設定を行います。

・必要環境

1. 開発者用 Bing Maps Key を取得

まず、Bing Maps サービスを利用したアプリケーションを作成する場合、Bing Maps Key を取得する必要があります。

アカウントの作成、キーの取得

 

2. Silverlight アプリケーション プロジェクトの作成と画面の構築

今回のサンプル用にプロジェクトを作成し、MainPage.xaml に都道府県、区市町村、住所を入力する欄と xamMap を貼り付けます。

image

MainPage.xaml

<UserControl x:Class="xamMap_Bing.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" 
    d:DesignWidth="400" 
    xmlns:ig="http://schemas.infragistics.com/xaml"
    Loaded="UserControl_Loaded" >

    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="210" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid>
            <Grid.Resources>
                <Style TargetType="TextBlock">
                    <Setter Property="VerticalAlignment" Value="Center" />
                    <Setter Property="HorizontalAlignment" Value="Right" />
                    <Setter Property="Margin" Value="5,0" />
                </Style>
                <Style TargetType="TextBox">
                    <Setter Property="Margin" Value="3" />
                </Style>
            </Grid.Resources>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="70" />
                <ColumnDefinition Width="70" />
                <ColumnDefinition Width="70" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <TextBlock Text="郵便番号" />
            <TextBlock Text="都道府県" Grid.Row="1" />
            <TextBlock Text="区市町村" Grid.Row="2" />
            <TextBlock Text="住所1" Grid.Row="3" />
            <TextBlock Text="住所2" Grid.Row="4" />
            <TextBox Name="PostalCode" Grid.Column="1" 
				Grid.ColumnSpan="2" />
            <TextBox Name="Region" Grid.Row="1" 
				Grid.Column="1" Grid.ColumnSpan="2" />
            <TextBox Name="City" Grid.Row="2" Grid.Column="1" 
				Grid.ColumnSpan="2"/>
            <TextBox Name="Address1" Grid.Row="3" Grid.Column="1" 
				Grid.ColumnSpan="2" />
            <TextBox Name="Address2" Grid.Row="4" Grid.Column="1" 
				Grid.ColumnSpan="2" />
            <Button Name="SearchPostalCode" 
				Content="郵便番号" Grid.Row="5" 
				Grid.Column="1" Margin="2" 
				Click="SearchPostalCode_Click" />
            <Button Name="SearchFullAddress" 
				Content="住所" Grid.Row="5" 
				Grid.Column="2" Margin="2" 
				Click="SearchFullAddress_Click" />
            <TextBlock Name="AddressArea" Grid.Row="6" 
				Grid.ColumnSpan="3" Margin="2" />
        </Grid>
        <ig:XamMap Grid.Column="1" Name="xamMap1" >
            <ig:XamMap.LogicalChildren>
                <ig:MapNavigationPane ig:XamDock.Edge="InsideBottom" 
                                      Orientation="Horizontal"
                                      />
            </ig:XamMap.LogicalChildren>
        </ig:XamMap>
    </Grid>
</UserControl>

3. 地理的画像情報サービスへの接続

オンラインヘルプを参考にして、Loaded イベントにおいて、地理的画像情報サービスへの接続を行います。

image

private void InitImageryService()
{
    ImageryMetadataRequest mapImgRequest = new ImageryMetadataRequest();
    mapImgRequest.Credentials = new Credentials();
    // 注:Bing Maps の本人キーが必要です
    mapImgRequest.Credentials.ApplicationId = this.BingMapsKey;
    mapImgRequest.Style = MapStyle.AerialWithLabels;
            
    // 地理的画像リクエストを処理するための Bing Mapsasync クライアント
    ImageryServiceClient imgService = new ImageryServiceClient(ImageServiceConfig);
    imgService.GetImageryMetadataCompleted += 
		new EventHandler<GetImageryMetadataCompletedEventArgs>(imgService_GetImageryMetadataCompleted);
    imgService.GetImageryMetadataAsync(mapImgRequest);

}

void imgService_GetImageryMetadataCompleted(object sender, GetImageryMetadataCompletedEventArgs e)
{
    ImageryMetadataResult result = e.Result.Results[0];
    this.xamMap1.MapTileSource = new Infragistics.Controls.Maps.BingMapsTileSource()
    {
        TilePath = result.ImageUri,
        SubDomains = new ObservableCollection<string>(result.ImageUriSubdomains)
    };
}

private void InitMapCoordinates()
{
    // 世界のサイズを定義します
    Point worldTopLeft = new Point(-180, 90);
    Point worldBottomRight = new Point(180, -90);

    // 測地座標をデカルト座標に変換します
    Point winTopLeft = this.xamMap1.MapProjection.ProjectToMap(worldTopLeft);
    Point winBottomRight = this.xamMap1.MapProjection.ProjectToMap(worldBottomRight);
    // Rect 構造、地図コントロールの WindowRect および WorldRect を作成します
    Rect winRect = new Rect()
    {
        X = Math.Min(winTopLeft.X, winBottomRight.X),
        Y = Math.Min(winTopLeft.Y, winBottomRight.Y),
        Width = Math.Abs(winTopLeft.X - winBottomRight.X),
        Height = Math.Abs(winTopLeft.Y - winBottomRight.Y)
    };
    this.xamMap1.IsAutoWorldRect = false;
    this.xamMap1.WindowZoomMaximum = 80;

    // 地図コントロールの WindowRect および WorldRect を変更します
    this.xamMap1.WindowRect = this.xamMap1.WorldRect = winRect;

}

4. Bing Maps Geocode Service への参照とロジックを実装

郵便番号、あるいは住所から経緯度を取得するため、3 と同様に Bing Maps の Geocode Service への参照を設定します。
サービス url は Bing Maps SOAP Services Address で確認することが出来ます。

image

サービスへは郵便番号、または住所データを基に経緯度取得するロジックを作成します。

#region 経緯度サービスの呼び出しと移動

private void GetPointFromService(string locationData, AddressType adressType)
{
    try
    {
        GeocodeRequest geocodeRequest = new GeocodeRequest();

        geocodeRequest.Credentials = 
			new xamMap_Bing.VEGeocodeServiceRefence.Credentials();
        geocodeRequest.Credentials.ApplicationId = this.BingMapsKey;

        // 日本限定
        geocodeRequest.Culture = "ja-JP";

        Address ad = new Address();
        ad.CountryRegion = "Japan";

        // 検索情報の設定
        switch (adressType)
        {
            case AddressType.PostalCode:
                ad.PostalCode = locationData;
                break;
            case AddressType.FullAddress:
                ad.AddressLine = locationData;
                break;
            default:
                break;
        }
        geocodeRequest.Address = ad;

        // サービス クライアントの作成
        GeocodeServiceClient geocodeService =
            new GeocodeServiceClient(GeoCodeServiceConfig);
        geocodeService.GeocodeCompleted += 
			new EventHandler<GeocodeCompletedEventArgs>(
							geocodeService_GeocodeCompleted);

        // リクエスト
        geocodeService.GeocodeAsync(geocodeRequest);
    }
    catch (Exception ex)
    {
        MessageBox.Show("サービスへのアクセス時に例外が発生しました");
    }
}

void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
    if (e.Result.ResponseSummary.StatusCode == 
			xamMap_Bing.VEGeocodeServiceRefence.ResponseStatusCode.Success)
    {
        if (e.Result.Results.Count > 0 && 
			e.Result.Results[0].Locations.Count > 0)
        {
            // 取得した緯度・経度へ移動します。
        }
        else
        {
            MessageBox.Show("経緯度が取得できませんでした");
        }
    }
}
        
#endregion

5. 経緯度からマップ表示位置を設定

経緯度が取得できれば後は表示位置とズームを行うことになります。XamMap.MapProjection.Project メソッドを使用すると経緯度から XamMap の座標を計算してくれます。

private void MoveMapToLocation(double longitude, double latitude)
{
    Point worldLocation = new Point(longitude, latitude);
    // 測地座標をデカルト座標に変換します
    Point winCenter =
        this.xamMap1.MapProjection.ProjectToMap(worldLocation);
            
    // 表示領域の設定を行います。
    Point worldTopLeft = new Point(longitude - 0.005,
                                latitude - 0.005);
    Point worldButtomRight = new Point(longitude + 0.005,
                                latitude + 0.005);

    Point winTopLeft = this.xamMap1.MapProjection.Project(worldTopLeft);
    Point winButtomRight = this.xamMap1.MapProjection.Project(worldButtomRight);

    Rect winRect = new Rect(
        Math.Min(winTopLeft.X, winButtomRight.X),
        Math.Min(winTopLeft.Y, winButtomRight.Y),
        Math.Abs(winTopLeft.X - winButtomRight.X),
        Math.Abs(winTopLeft.Y - winButtomRight.Y));

    this.xamMap1.WindowRect = winRect;
    this.xamMap1.WindowCenter = winCenter;
}

6. ボタンクリックイベントで位置情報を取得

全てのコードは次のようになります。

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using xamMap_Bing.VEImageryServiceReference;
using System.Collections.ObjectModel;
using xamMap_Bing.VEGeocodeServiceRefence;
using System.Text;

namespace xamMap_Bing
{
    public partial class MainPage : UserControl
    {
        #region プロパティ

        // ここに Bing Map Key を設定します。
        private string BingMapsKey = "BING_MAP_KEY";
        private string ImageServiceConfig = "BasicHttpBinding_IImageryService";
        private string GeoCodeServiceConfig = "BasicHttpBinding_IGeocodeService";

        #endregion 

        #region コンストラクタ

        public MainPage()
        {
            InitializeComponent();
        }

        #endregion

        #region 地理的画像サービスへの接続

        private void InitImageryService()
        {
            ImageryMetadataRequest mapImgRequest = new ImageryMetadataRequest();
            mapImgRequest.Credentials = 
				new xamMap_Bing.VEImageryServiceReference.Credentials();
            // 注:Bing Maps の本人キーが必要です
            mapImgRequest.Credentials.ApplicationId = this.BingMapsKey;
            mapImgRequest.Style = MapStyle.AerialWithLabels;
            
            // 地理的画像リクエストを処理するための Bing Mapsasync クライアント
            ImageryServiceClient imgService = new ImageryServiceClient(ImageServiceConfig);
            imgService.GetImageryMetadataCompleted += 
				new EventHandler<GetImageryMetadataCompletedEventArgs>(
					imgService_GetImageryMetadataCompleted);
            imgService.GetImageryMetadataAsync(mapImgRequest);
        }

        void imgService_GetImageryMetadataCompleted(object sender, GetImageryMetadataCompletedEventArgs e)
        {
            ImageryMetadataResult result = e.Result.Results[0];
            this.xamMap1.MapTileSource = 
				new Infragistics.Controls.Maps.BingMapsTileSource()
            {
                TilePath = result.ImageUri,
                SubDomains = new ObservableCollection<string>(result.ImageUriSubdomains)
            };
        }

        #endregion

        #region ヘルパーメソッド

        private void InitMapCoordinates()
        {
            // 世界のサイズを定義します
            Point worldTopLeft = new Point(-180, 90);
            Point worldBottomRight = new Point(180, -90);

            // 測地座標をデカルト座標に変換します
            Point winTopLeft = this.xamMap1.MapProjection.ProjectToMap(worldTopLeft);
            Point winBottomRight = this.xamMap1.MapProjection.ProjectToMap(worldBottomRight);
            // Rect 構造、地図コントロールの WindowRect および WorldRect を作成します
            Rect winRect = new Rect()
            {
                X = Math.Min(winTopLeft.X, winBottomRight.X),
                Y = Math.Min(winTopLeft.Y, winBottomRight.Y),
                Width = Math.Abs(winTopLeft.X - winBottomRight.X),
                Height = Math.Abs(winTopLeft.Y - winBottomRight.Y)
            };
            this.xamMap1.IsAutoWorldRect = false;
            this.xamMap1.WindowZoomMaximum = 80;

            // 地図コントロールの WindowRect および WorldRect を変更します
            this.xamMap1.WindowRect = this.xamMap1.WorldRect = winRect;

        }

        private void MoveMapToLocation(double longitude, double latitude)
        {
            Point worldLocation = new Point(longitude, latitude);
            // 測地座標をデカルト座標に変換します
            Point winCenter =
                this.xamMap1.MapProjection.ProjectToMap(worldLocation);

            // 表示領域の設定を行います。
            Point worldTopLeft = new Point(longitude - 0.005,
                                        latitude - 0.005);
            Point worldButtomRight = new Point(longitude + 0.005,
                                        latitude + 0.005);

            Point winTopLeft = this.xamMap1.MapProjection.Project(worldTopLeft);
            Point winButtomRight = this.xamMap1.MapProjection.Project(worldButtomRight);

            Rect winRect = new Rect(
                Math.Min(winTopLeft.X, winButtomRight.X),
                Math.Min(winTopLeft.Y, winButtomRight.Y),
                Math.Abs(winTopLeft.X - winButtomRight.X),
                Math.Abs(winTopLeft.Y - winButtomRight.Y));

            this.xamMap1.WindowRect = winRect;
            this.xamMap1.WindowCenter = winCenter;
        }


        #endregion

        #region 経緯度サービスの呼び出しと移動

        private void GetPointFromService(string locationData, AddressType adressType)
        {
            try
            {
                GeocodeRequest geocodeRequest = new GeocodeRequest();

                geocodeRequest.Credentials = 
                    new xamMap_Bing.VEGeocodeServiceRefence.Credentials();
                geocodeRequest.Credentials.ApplicationId = this.BingMapsKey;

                // 日本限定
                geocodeRequest.Culture = "ja-JP";

                Address ad = new Address();
                ad.CountryRegion = "Japan";

                // 検索情報の設定
                switch (adressType)
                {
                    case AddressType.PostalCode:
                        ad.PostalCode = locationData;
                        break;
                    case AddressType.FullAddress:
                        ad.AddressLine = locationData;
                        break;
                    default:
                        break;
                }
                geocodeRequest.Address = ad;

                // サービス クライアントの作成
                GeocodeServiceClient geocodeService =
                    new GeocodeServiceClient(GeoCodeServiceConfig);
                geocodeService.GeocodeCompleted += 
                    new EventHandler<GeocodeCompletedEventArgs>(
                        geocodeService_GeocodeCompleted);

                // リクエスト
                geocodeService.GeocodeAsync(geocodeRequest);
            }
            catch (Exception ex)
            {
                MessageBox.Show("サービスへのアクセス時に例外が発生しました");
            }
        }

        void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
        {
            if (e.Result.ResponseSummary.StatusCode == 
                xamMap_Bing.VEGeocodeServiceRefence.ResponseStatusCode.Success)
            {
                if (e.Result.Results.Count > 0 && e.Result.Results[0].Locations.Count > 0)
                {
                    // 取得した緯度・経度へ移動します。
                    this.MoveMapToLocation(
                        e.Result.Results[0].Locations[0].Longitude,
                        e.Result.Results[0].Locations[0].Latitude);
                }
                else
                {
                    MessageBox.Show("経緯度が取得できませんでした");
                }
            }
        }
        #endregion

        #region イベントハンドラ

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            // 地理情報サービスの初期化
            InitImageryService();
            // 地図情報の設定
            InitMapCoordinates();

        }

        private void SearchPostalCode_Click(object sender, RoutedEventArgs e)
        {
            this.GetPointFromService(this.PostalCode.Text, AddressType.PostalCode);
        }

        private void SearchFullAddress_Click(object sender, RoutedEventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(this.Region.Text);
            sb.Append(" ");
            sb.Append(this.City.Text);
            sb.Append(" ");
            sb.Append(this.Address1.Text);
            sb.Append(" ");
            sb.Append(this.Address2.Text);
            this.GetPointFromService(sb.ToString(), 
                AddressType.FullAddress);
        }

        #endregion 
    }

    public enum AddressType
    {
        PostalCode,
        FullAddress
    }
}

インフラジスティックスの住所を入れると・・・

image

このマップと ShapeFile を組み合わせることもできます。

サンプルソリューション

Bing Maps については Microsoft MVP でもある、松江さんがここで連載されていますのでこちらも是非ご参考に!

使ってみよう! Bing API/SDK

Posted: 20 Jan 2011, 14:36

Comments

WPF と UX なBlog said:

前回 のエントリで予告していたように今回は xamMap で Bing Maps SOAP Services を利用し、地図情報の表示、経緯度の取得までを行います。なお、セッションサンプルでは LightSwitch

# January 20, 2011 12:48 AM

Daizen Ikehara said:

さて、この 2 週間は週末の旅が目白押しでした。そこで発表させていただいたスライド &amp; デモを公開させて頂きますので、よろしければご参考にしていただければと思います。 1/29 Hokuriku.NET

# February 7, 2011 12:25 AM
Anonymous comments are disabled