自分の現在位置を取得して表示するサンプルプログラム

2013年6月27日(木)
薬師寺 国安

次に、ソリューションエクスプローラー内のMainWindow.xamlを展開して表示される、MainWindow.xaml.vbをダブルクリックしてリスト2のコードを記述します。

ロジックコードを記述する

リスト1 (MainWindow.xaml.vb)

Option Strict On

コンピュータの地理的位置にアクセスできるようにするクラスの含まれる、Windows.Devices.Geolocation名前空間をインポートします。

Imports Windows.Devices.Geolocation

Bing Mapsに関するクラスの含まれる、Bing.Maps名前空間をインポートします。

Imports Bing.Maps

UIに関するクラスの含まれるWindows.UI名前空間をインポートします。PushPinの色を設定する場合等に必要です。

Imports Windows.UI

アプリケーションウインドウやウインドウ対話を作成し管理するサポートと、ウインドウ上の入力イベントを処理するクラスの含まれる、Windows.UI.Core名前空間をインポートします。

Imports Windows.UI.Core

最新のHTTPアプリケーション用のプログラミング インターフェイスを提供するクラスの含まれる、System.Net.Http名前空間をインポートします。

Imports System.Net.Http

コンテキストメニューおよびメッセージダイアログのサポートを提供するクラスの含まれる、Windows.UI.Popups名前空間をインポートします。

Imports Windows.UI.Popups

Public NotInheritable Class MainPage
  Inherits Page

現在の地理的位置にアクセスするクラスである、Geolocatorクラスのメンバ変数myGeolocatorを宣言します。

  Dim myGeolocator As Geolocator
  
  Dim myLatitude As String
  Dim myLongitude As String

Windowsランタイムコアイベントメッセージディスパッチャを提供するクラスである、CoreDispatcherクラスのメンバ変数、myCoreDispacherを宣言します。

  Dim myCoreDispacher As CoreDispatcher

「Yahooで取得したアプリケーションID」で、定数メンバ変数AppIDを初期化します。

  ConstAppID As String = "Yahooで取得したアプリケーションID"

ページがアクティブになった時の処理

myGeolocatorオブジェクトが作成されていない場合は、新しいGeolocatorクラスのインスタンスmyGeolocatorオブジェクトを作成します。
場所認識の精度レベルを表す、DesiredAccuracy プロパティにはDefaultを指定しておきます。Default以外にHighがありますが、パフォーマンスが低下する恐れがありますので、Defaultを指定しています。

Window.Current.CoreWindow.Dispatcherで、現在アクティブになっている、ウインドウの内部コアオブジェクトのイベントディスパッチャを取得して、myCoreDispacherで参照します。

AddHandlerステートメントで、場所が更新された時のPositionChangedイベント時のイベントハンドラ、myGeolocator_PositionChangedを追加します。

同じく、AddHandlerステートメントで、更新された場所を提供するGeolocatorの機能が変更された時に発生する、StatusChanged時のイベントハンドラ、myGeolocator_StatusChangedを追加します。

  Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
    If myGeolocator Is Nothing = True Then
      myGeolocator = New Geolocator
      myGeolocator.DesiredAccuracy = PositionAccuracy.Default
      myCoreDispacher = Window.Current.CoreWindow.Dispatcher
    End If
    AddHandlermyGeolocator.PositionChanged, AddressOfmyGeolocator_PositionChanged
    AddHandlermyGeolocator.StatusChanged, AddressOfmyGeolocator_StatusChanged
  End Sub

場所が変更された時の処理

myCoreDispacher.RunAsyncメソッドで、イベントディスパッチャを実行し、ディスパッチされたイベントの結果を非同期に返します。ディスパッチャの優先順位は標準のNormalを指定しています。

緯度と経度のデータや都市の住所データを含めることができるGeoPositionクラス型の変数psoを宣言し、PositionChangedイベントに関連付けられた場所データを取得します。

Clearメソッドで、地図内を一度クリアしておきます。

新しいPushpinクラスのインスタンスmyPinオブジェクトを作成します。ピンの背景色をCrimsonに指定します。

地理的位置に関連付けされた緯度と経度で初期化された、新しいLocationクラスのインスタンスmyLocationオブジェクトを作成します。Locationクラスは、地図上の場所の標高と座標値を含むクラスです。

MapLayerクラスのSetPositionメソッドで、マップレイヤー内にピンの位置を設定します。myMapにAddメソッドでピンを追加します。SetViewメソッドで、指定された中心部に位置、ズーム レベル、方位、およびピッチにマップビューを設定します。この場合myLocationの位置に16レベルでズームインします。

現在位置の住所を取得するWeb APIのURLを設定します。latに現在の緯度、lonには現在の経度、appidにはYahooのキーを指定し、変数myUriに格納しておきます。

新しいHttpClientクラスのインスタンスmyHttpClientオブジェクトを作成します。HttpClientクラスには、URIで識別されるリソースにHTTP要求を送信し、そのリソースからHTTP応答を受信するための基本クラスが含まれています。

GetStringAsyncメソッドでmyUriの結果を、文字列として返し、変数resultAddressに格納します。GetStringAsyncメソッドは、指定URIにGET要求を送信し、非同期操作で応答本体を文字列として返すメソッドです。

返される文字列はXML形式になっています。このXMLのルート要素には、名前空間や不要な属性が定義されていて、内容を取得する際の邪魔(-_-;)になりますので、Replace関数で、ルート要素()だけに置換しています。

XElement.Parseメソッドで置換された結果のXMLが格納されている、resultAddressを文字列として読み込みます。

読み込んだXMLから

要素の内容を取得して、変数myAddressに格納しておきます。

新しいStackPanelのインスタンスmyStackPanelオブジェクトを作成します。Marginプロパティに5を指定して余白を設けます。背景色をNavyに指定します。このStackPanelオブジェクトのインスタンスを、非表示としておきます。

新しいTextBlockのインスタンスmyTextBlockオブジェクトを作成します。文字色をRedに指定します。文字サイズに24を指定し、パディングに10を指定します。Textプロパティに住所を格納している変数myAddressと文字列「辺り」を連結して指定します。

myStackPanelオブジェクトにAddメソッドで住所の設定された、myTextBlockを追加します。

MapLayerクラスのSetPositionメソッドで、マップレイヤー内にmyStackPanelオブジェクトの位置を設定します。MapLayerクラスは、地図上の要素の位置を保持しているマップレイヤーを表すクラスです。

myMapにAddメソッドでmyStackPanelオブジェクトを追加します。myStackPanelは最初の状態では非表示になっているのでわかりませんが、ピンの位置にStackPanelオブジェクトが表示されることになります。

AddHandlerステートメントでピンをタップした時のイベントハンドラを追加します。イベントハンドラ内では、myStackPanelオブジェクトを表示状態にします。

AddHandlerステートメントでmyStackPanelをタップした時のイベントハンドラを追加します。イベントハンドラ内では、myStackPanelオブジェクトを非表示状態にします。

非同期処理で行われるためメソッドの先頭にAsyncを追加します。

  Private Async Sub myGeolocator_PositionChanged(sender As Geolocator, args As PositionChangedEventArgs)
    Await myCoreDispacher.RunAsync(CoreDispatcherPriority.Normal, Async Sub()
        Dim pos As Geoposition = args.Position
       myMap.Children.Clear()
        Dim myPin As New Pushpin
        myPin.Background = New SolidColorBrush(Colors.Crimson)
        Dim myLocation = New Location(CDbl(pos.Coordinate.Latitude), CDbl(pos.Coordinate.Longitude))
        MapLayer.SetPosition(myPin, myLocation)
        myMap.Children.Add(myPin)
        myMap.SetView(myLocation, 16)
        
        Dim myUri As String = String.Format("http://reverse.search.olp.yahooapis.jp/OpenLocalPlatform/V1/reverseGeoCoder?lat={0}&lon={1}&appid={2}", pos.Coordinate.Latitude, pos.Coordinate.Longitude, AppID)
        Dim myHttpClient As New HttpClient
        Dim resultAddress = Await myHttpClient.GetStringAsync(myUri)
        resultAddress = resultAddress.Replace("<YDF firstResultPosition=" &ChrW(34) & "1" &ChrW(34) & " totalResultsAvailable=" &ChrW(34) & "1" &ChrW(34) & " totalResultsReturned=" &ChrW(34) & "1" &ChrW(34) & " xmlns=" &ChrW(34) & "http://olp.yahooapis.jp/ydf/1.0" &ChrW(34) & ">", "<YDF>")
        Dim httpDoc As XElement = XElement.Parse(resultAddress)
        Dim myAddress = httpDoc.Descendants("Address").Value
        Dim myStackPanel As New StackPanel
        myStackPanel.Margin = New Thickness(5)
        myStackPanel.Background = New SolidColorBrush(Colors.Navy)
        myStackPanel.Visibility = Xaml.Visibility.Collapsed
        Dim myTextBlock As New TextBlock
        myTextBlock.Foreground = New SolidColorBrush(Colors.Red)
        myTextBlock.FontSize = 24
        myTextBlock.Padding = New Thickness(10)
        myTextBlock.Text = myAddress& " 辺り"
        myStackPanel.Children.Add(myTextBlock)
        MapLayer.SetPosition(myStackPanel, New Location(CDbl(pos.Coordinate.Latitude), CDbl(pos.Coordinate.Longitude)))
        myMap.Children.Add(myStackPanel)
          AddHandlermyPin.Tapped, Sub()
            myStackPanel.Visibility = Xaml.Visibility.Visible
          End Sub
          
          AddHandlermyStackPanel.Tapped, Sub()
            myStackPanel.Visibility = Xaml.Visibility.Collapsed
          End Sub
    End Sub)
  End Sub

Geolocatorの機能が変更された時に発生する処理

Geolocatorオブジェクトの更新後の状態を、変数positionStatusで参照します。

Select Case文で条件分岐を行います。場所データを提供するGeolocatorオブジェクトがDisabledであった場合、つまり、場所プロバイダーが無効であった場合は、RunAsyncメソッドでディスパッチされたイベントの結果を非同期に返します。ディスパッチャの優先順位は標準のNormalを指定しています。

この場合は、「位置情報を取得できません。GPSおよび位置情報取得可能なPCでお試しください。」というメッセージボックスを表示させ、処理を抜けます。

非同期で行われるためメソッドの先頭にAsyncを追加します。

Private Async Sub myGeolocator_StatusChanged(sender As Geolocator, args As StatusChangedEventArgs)
    Dim positionStatus = args.Status
    Select Case positionStatus
      Case Windows.Devices.Geolocation.PositionStatus.Disabled
        Await myCoreDispacher.RunAsync(CoreDispatcherPriority.Normal, Async Sub()
                                                                      Dim message As New MessageDialog("位置情報を取得できません。GPSおよび位置情報取得可能なPCでお試しください。")
                                                                      Await message.ShowAsync
                                                                      Exit Sub
                                                                    End Sub)
    End Select
  End Sub
End Class

アイコンの作成

ソリューションエクスプローラーのAssetsフォルダ内には、4つのpngファイルが入っています(表1)。

表1:Assetsフォルダ内に入っているpngファイルの種類

ファイル名 サイズ
Logo.png 150×150
SmallLogo.png 30×30
SplashScreen.png 620×300
StoreLogo.png 50×50

表1の画像はデフォルトでは、□に×の画像になっています。ストアの審査では、このままの画像では審査に受かりませんので、4種類のアイコンを作る必要があります。このサンプルは実際にストアで審査の通ったアプリですので、Assetsフォルダ内には筆者の作成したアイコンが収められていますので、見てみてください。SplashScreen.pngはアプリを起動した際に、一瞬最初に表示される画像です。スタート画面にピン止めされる画像はデフォルトでは150×150のLogo.pngが使用されます。これを長方形の画像にしたい場合は、310×150サイズのpng画像を作成し、WideLogo.png(任意の名前でOK)としてAssetsフォルダに追加しておきます。

次にpackage.appxmanifestをダブルクリックして開きます。「アプリケーションUI」タブ内の「タイトルイメージとロゴ」というパネルに画像が表示されています(図16)。

図16:「ロゴ」画像が表示されている(クリックで拡大)

図16から、「ワイドロゴ」を選択して310×150pxの横にある[…]ボタンをクリックして、Assetsフォルダ内のWideLogo.pngを指定します。初めて指定した場合は、画像が表示されずに赤丸の×が表示されます。
Assetsフォルダ内を見てみると、WideLogo.pngに-100といった不要なファイルが追加されていますので、これを削除してください。すると図17のように無事ワイドロゴが表示されます。実行すると、スタート画面にはこの長方形のワイドロゴがピン止めされます。

図17:ワイドロゴが指定された(クリックで拡大)

今回はここまでです。ありがとうございました。

筆者からのお知らせ

筆者はWindowsストアでアプリを公開しています。チャームの検索からWindowsストアを選択して、検索欄に、kuniyasuまたはYakushijiKuniyasuと入力すると、公開されているアプリの一覧が表示されます。上記はどちらも私のアカウントですので、興味のある方は是非ダウンロードして使ってみてください。

  • 自分の現在位置を取得して表示するプログラム

薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています