酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

Windows PhoneでGeoCoordinateWatcher(GPS/位置情報測位)クラスを使って位置情報を取得する

概要

Windows Phone Location Serviceへアクセスする手段を提供してます。

Windows Phone 7.5("Mango"アップデート)からはWindows Phone エミュレータの標準機能としてGPSシミュレータが付きますが、それ以前の開発環境では「GPSをエミュレートする」を参考にして頂きながら、PC上での試験をおこなうようにするとテストがスムーズかもしれません。

名前空間:System.Device.Location

  • System.Object
    • System.Device.Location.GeoCoordinateWatcher

Tips

位置情報を取得する

取得したロケーションサービス(位置情報を扱う仕組み)のデータを、以下の様なUIで表示させてみましょう。一番上からロケーションサービスのステータス、緯度(latitude)、経度(longitude)の値を表示させています。

f:id:ch3cooh393:20141113133712p:plain

System.Device.Location名前空間のクラスを使用して位置情報を取得します。参照の追加ダイアログにて「System.Device」を参照しておきます。更にusingディレクティブに追加しておきましょう。

using System.Device.Location; // for Location Service
using System.Windows;
using Microsoft.Phone.Controls;
using System.Windows.Navigation;

GPSデバイスから取得した位置情報をアプリケーションで受け取るにGeoCoordinateWatcherクラスを使用します。

下記のサンプルコードではページ遷移後にOnNavigatedToメソッドが実行され、GeoCoordinateWatcherインスタンスの生成をおこない、位置情報の取得を開始します。

物理的なセンサーデバイスからの入力を受け取るため、位置情報を取得するのは殆どのケースでは1秒未満に位置情報が取得できますが、取得が遅い場合1分掛かることも有り得ます。

高精度で位置情報を取得したい場合はコンストラクタ引数にGeoPositionAccuracy.Highを指定しています。精度は低くても測定速度を上げたい場合はGeoPositionAccuracy.Defaultを指定します。

namespace GeoCoordinateWatcherTest {
    public partial class MainPage : PhoneApplicationPage {
        // コンストラクター
        public MainPage() {
            InitializeComponent();
        }

        GeoCoordinateWatcher watcher;

        // ページ遷移されてきた時に呼び出される
        protected override void OnNavigatedTo(NavigationEventArgs e) {
            
            // GeoCoordinateWatcherのインスタンスを生成する
            // Highを指定すると高精度で位置測定する
            watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
            // 精度よりも測定速度を優先する場合はDefaultを指定する
            //watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);

            // 位置が変更されたことを判定する最短距離(単位:メートル)
            watcher.MovementThreshold = 20;

            // 位置が変更された時に発生するイベントハンドラを追加
            watcher.PositionChanged += watcher_PositionChanged;

            // ロケーションサービスの状態変化時に発生するイベントハンドラを追加
            watcher.StatusChanged += watcher_StatusChanged;

            // データの取得を開始する
            watcher.Start();
        }

以上で位置情報の取得を開始します。ロケーションサービスのステータス変更イベント、位置が変更したイベントの取得の仕方について後述します。

ロケーションサービスの状態が変化された時のイベント

ロケーションサービスの状態が変化するとStatusChangedイベントが発生します。ここではイベントハンドラで状態を受け取り、TextBlockコントロールに日本語で説明を表示させています。

TextBlockの値を変更するにはUIスレッドからおこなう必要があります。ただ、GeoCoordinateWatcherからのイベントは別のスレッドから返ってくる為、BeginInvokeメソッドを使ってUIスレッド上で非同期に実行しています。

// 状態が変更された場合に呼ばれるイベントハンドラ
void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e) {
    
    // TextBlockの値を変更したいのでUIスレッド上で実行させる
    Deployment.Current.Dispatcher.BeginInvoke(() => {

        // ステータスの内容によって表示する文言を変更する
        switch (e.Status) {
            case GeoPositionStatus.Initializing:
                labelStatus.Text = "初期化中";
                break;
            case GeoPositionStatus.Ready:
                labelStatus.Text = "動作中";
                break;
            case GeoPositionStatus.NoData:
                labelStatus.Text = "動作中だが、位置情報が取得できていない";
                break;
            case GeoPositionStatus.Disabled:
                labelStatus.Text = "非サポートか無効にされています";
                break;
        }
    });
}

移動して位置情報が変更された時のイベント

前回測位した位置より移動し、MovementThresholdプロパティに設定した最短距離以上移動した場合にPositionChangedイベントが発生します。ここではイベントハンドラで位置情報を受け取り、TextBlockコントロールに整形された値を表示しています。

こちらのイベントも別スレッドで通知される為、BeginInvokeメソッドを使用しています。

// 位置情報が変更された場合に呼ばれるイベントハンドラ
void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e) {

    // TextBlockの値を変更したいのでUIスレッド上で実行させる
    Deployment.Current.Dispatcher.BeginInvoke(() => {
        
        double latitude = e.Position.Location.Latitude;
        double longitude = e.Position.Location.Longitude;

        labelLatitude.Text = string.Format("{0:0.0000}", latitude);
        labelLongitude.Text = string.Format("{0:0.0000}", longitude);
    });
}

参照

関連記事