Windows Phoneの地図と位置データ



まず、Windows Phoneのマップへのインターフェイスを提供するマップコントロールから始めます。 Windows Phoneアプリケーションテンプレートから新しいプロジェクトを作成し、ExploreMapControlという名前を付けましょう。



プロジェクトが作成されたら、それが参照するライブラリを確認します。



次に、最小化されている場合はツールボックスを展開し、Mapコントロールをアプリケーションインターフェイスのデザイナーにドラッグします。







プロジェクトがMicrosoft.Phone.Controls.Mapを参照するようになりました。







MainPage.xamlページをダブルクリックして、XAMLコードの変更点を確認します。 私の名前空間からマップコントロールが追加されました。

<my:Map Height="50" HorizontalAlignment="Left" Margin="201,198,0,0" Name="map1" VerticalAlignment="Top" Width="100" />
      
      





XAMLドキュメントのタイトルを見ると、この名前空間が何であるかがわかります。

 xmlns:my="clr-namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls.Maps"
      
      





名前空間名がその内容と一致するように、myをmapに置き換えましょう。

 xmlns:map="clr-namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls.Maps"
      
      







 <map:Map Height="50" HorizontalAlignment="Left" Margin="201,198,0,0" Name="map1" VerticalAlignment="Top" Width="100" />
      
      





MapコントロールのXAMLコードを編集するか、Properitesパネルを使用して、要素が空き領域の大部分を占めるようにし、要素の名前をMyMapに変更します。

 <map:Map Name="MyMap"/>
      
      







アプリケーション(F5)を起動し、実行時にコントロールがどのように見えるかを確認します。







ログインの詳細が間違っていることを示す白いバナーが画面中央に表示されていますか? これは、このコントロールがBingのマップサービスを使用し、それを使用するには登録が必要だからです。 キーを登録して、Bing Mapsポータル( http://www.bingmapsportal.com)で受け取ることができます

登録の最後に、開発者は文字列キーを受け取ります。これは、コントロール要素のCredentialsProviderプロパティで指定する必要があり、リソースまたはデータに転送することもできます。

シンプルなマップコントロールを追加します。ズームアウト/ズームアウト、マップ表示モードの変更。

 <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <map:Map Name="MyMap"> <Button Name="ZoomIn" Content="+" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="60" Width="60" Margin="-100,0,0,-5" Click="ZoomIn_Click" FontWeight="Bold" Padding="0,-9,0,0"/> <Button Name="ZoomOut" Content="-" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="60" Width="60" Margin="100,0,0,-5" Click="ZoomOut_Click" FontWeight="Bold" Padding="0,-9,0,0" /> <Button Name="LayoutChange" Content="L" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="60" Width="60" Margin="0,0,0,-5" FontWeight="Bold" Padding="0,-9,0,0" Click="LayoutChange_Click"/> </map:Map> </Grid>
      
      





そして、これらのイベントをアプリケーションコードで処理します。

 private void ZoomIn_Click(object sender, RoutedEventArgs e) { MyMap.ZoomLevel += 1; } private void ZoomOut_Click(object sender, RoutedEventArgs e) { MyMap.ZoomLevel -= 1; } private void LayoutChange_Click(object sender, RoutedEventArgs e) { if (MyMap.Mode is RoadMode) { MyMap.Mode = new AerialMode(true); } else { MyMap.Mode = new RoadMode(); } }
      
      





usingブロックに次のディレクティブを忘れずに追加してください。

 using Microsoft.Phone.Controls.Maps;
      
      





アプリケーション(F5)を起動し、コントロールが意図したとおりに機能していることを確認します。 Metroの設計に従って、アプリケーションウィンドウの下部にあるボタンを備えたパネルをアプリケーションバーとして配置する必要がありますが、これは例を単純化するために、より単純なオプションを使用する場合のみです。 独立した演習として、ボタンを削除し、XAMLファイル内のサンプルアプリケーションバーコードのコメントを解除して、Metroスタイルに従ってアプリケーションを作り直すことができます。



次に、電話で利用できるジオロケーションサービスに移りましょう。 このサービスは、Wi-Fiから受信した情報、セルラー通信、GPS受信機からのデータの組み合わせを使用して情報を提供します。 ここで、ジオロケーションサービスによって提供される機能をアプリケーションに追加します。



まず、usingブロックに次のディレクティブを追加します。

 using Microsoft.Devices.Sensors;
      
      





これで、ロケーション/ロケーションサービスを使用する準備が整いました。



最初に、プログラムから簡単な追加を作成します。これは、サービスから受信した地理位置情報データに従って地図を中央に配置します。

GeoCoordinateWatcher型の変数の定義をクラスに追加します。これにより、位置情報サービスを初期化し、それらからデータを取得できます。

 private GeoCoordinateWatcher myGeoWatcher;
      
      





クラスコンストラクターで、加速度計に関連するコードの直後に、サービスステータス変更イベント(利用できない、準備ができていないなど)および位置変更イベントの初期化および登録コードを追加します。

 yGeoWatcher = new GeoCoordinateWatcher(); myGeoWatcher.MovementThreshold = 100.0f; myGeoWatcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(myGeoWatcher_StatusChanged); myGeoWatcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(myGeoWatcher_PositionChanged);
      
      





優れたアプリケーションは、ジオサービスのステータスを正しく処理する必要があります。 データを常に生成できるわけではなく、初期化にかなりの時間を費やす可能性があります。 まず、エミュレータでアプリケーションをテストするため、ハンドラーを空のままにします。このような問題はありません。

また、アプリケーションの最初のバージョンでは、エミュレーターの使用を考慮に入れて、アプリケーションの読み込みを遅くしないように、位置情報サービスの起動を別のストリームに配置する方が適切です。クラスコンストラクターでサービスを起動します。

 myGeoWatcher.TryStart(false, TimeSpan.FromSeconds(60));
      
      





Visual StudioがStatusChangedおよびPositionChangedイベントハンドラーを自動的に生成した場合、NotImplemented例外を発生させるこれらのメソッドのコードをコメント化または削除します。

 throw new NotImplementedException();
      
      





PositionChangedイベントハンドラーで、位置を変更するときにマップを中央に配置するコードを追加します。

 void myGeoWatcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e) { MyMap.Center = e.Position.Location; }
      
      







アプリケーション(F5)を起動し、エミュレーターの機能を使用して位置情報データをエミュレートし、プログラムの動作を確認します。 ズームインして、位置決めが正しく行われていることを確認します。





次のステップであるプログラムを改善するには、別のスレッドでサービスを起動し、位置情報データのステータスバーを追加し、地図上に位置を示すポイントを作成します。

スレッドを使用するには、次のディレクティブをusingブロックに追加します。

 using System.Threading;
      
      





コンストラクターで、サービスを開始する前に、コードを追加します。

 new Thread(startMyGeoWotcher).Start();
      
      





その後、startMyGeoWotcherという名前の値を受け入れたり返したりしない関数を作成し、サービス起動コードをそこに転送します。

 void startMyGeoWotcher() { myGeoWatcher.TryStart(false, TimeSpan.FromSeconds(60)); }
      
      





TextBlockコントロールを追加して、位置情報サービスのステータスを表示します

 <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <StackPanel> <TextBlock Name="GeoStatus" HorizontalAlignment="Center" VerticalAlignment="Top" Text="Geo Status .." /> <map:Map Name="MyMap" Height="580"> <Button Name="ZoomIn" Content="+" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="60" Width="60" Margin="-100,0,0,-5" Click="ZoomIn_Click" FontWeight="Bold" Padding="0,-9,0,0"/> <Button Name="ZoomOut" Content="-" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="60" Width="60" Margin="100,0,0,-5" Click="ZoomOut_Click" FontWeight="Bold" Padding="0,-9,0,0" /> <Button Name="LayoutChange" Content="L" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="60" Width="60" Margin="0,0,0,-5" FontWeight="Bold" Padding="0,-9,0,0" Click="LayoutChange_Click"/> </map:Map> </StackPanel> </Grid>
      
      





ステータス出力をStatusChangedハンドラーに追加します。

 void myGeoWatcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e) { switch (e.Status) { case GeoPositionStatus.Disabled: if (myGeoWatcher.Permission == GeoPositionPermission.Denied) { GeoStatus.Text = " "; } else { GeoStatus.Text = "    "; } break; case GeoPositionStatus.Initializing: GeoStatus.Text = " "; break; case GeoPositionStatus.NoData: GeoStatus.Text = "   "; break; case GeoPositionStatus.Ready: GeoStatus.Text = "   "; break; } }
      
      





最後に、位置変更イベントハンドラーで、マップにポイント設定を追加します。

プッシュピン変数をクラスに追加します。

 private Pushpin myPushpin;
      
      





クラスコンストラクターで作成しましょう。

 myPushpin = new Pushpin();
      
      





位置変更ハンドラーで、現在の位置に設定し、存在しない場合はマップに追加します。

 myPushpin.Location = e.Position.Location; if (!MyMap.Children.Contains(myPushpin)) MyMap.Children.Add(myPushpin);
      
      





アプリケーション(F5)を起動し、エミュレーターの機能を使用して位置情報データをエミュレートし、プログラムの動作を確認します。 ズームインして、ポイントの位置と設定が正しいことを確認します。 ジオロケーションサービスの表示状態も確認してください。





UPD :コメントandrew_kaneに正しく記述されています。 プールのスレッドを使用するのがより適切な方法です。



以下は、プールのスレッドを操作するために変更する必要があり、呼び出す必要のないコードです
 new Thread(...).Start();
      
      





代わりに

 new Thread(startMyGeoWotcher).Start();
      
      





次のコードを記述する必要があります。

 ThreadPool.QueueUserWorkItem(startMyGeoWotcher, myGeoWatcher);
      
      





プールを使用するには静的メソッドが必要であり、オブジェクトを静的にするか、パラメーターとして渡すかの2つのオプションがあるため、オブジェクトをメソッドに渡す必要があります。



今、あなたはメソッドを書き直す必要があります
 startMyGeoWotcher
      
      



次のようになります。

 static void startMyGeoWotcher(object GeoWatcher) { ((GeoCoordinateWatcher)GeoWatcher).TryStart(false, TimeSpan.FromSeconds(60)); }
      
      







便利なリンク:

MSDNのWindows Phone開発センター

Windows Phone SDK 7.1

ロシア語でのWindows Phone開発フォーラム



All Articles