WPFでBingMapsを使う

この間書いたポストの中に出てきたBingMapをWPFアプリケーションで使う方法を紹介します。
ブラウザアプリで使う場合、迷わずMaps Silverlight Controlを使ってくださいね(このネタは誰か別のエバが書いているのでそちらを参照してね)。

さて、ここでは、WPFアプリケーションにBingMapsを埋め込む簡単な方法を紹介します。現在のところWindows Sensor APIは、COMのWrapperを噛まさないと、Silverlightからはアクセスできないので、BingMapsをセンサーでコントロールしたい、といったような場合は、こちらが便利。

まずは、WPFアプリケーションプロジェクトを一つ作成し、WebBrowserコントロールをツールボックスからドラッグ&ドロップして貼り付けます。

<Window x:Class="WpfApplLocation.MainWindow"        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"        Title="MainWindow" Height="600" Width="820">    <StackPanel Orientation="Vertical">        <WebBrowser Name="webBrowser1" MinHeight="500" />    </StackPanel></Window>

WebBrowserコントロールの、SourceプロパティにURLを設定すると、そのURLの内容が表示されます。例えばTextBoxをXAML上に配置して、そのTextBoxの文字列と、Sourceプロパティを連結すると、簡単なブラウザをWeb上で構築することも可能です。

ここでは、以下のようなHTMLファイルをプロジェクトに追加します。名前は、BingMapCtrl.htmとしておきます。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>   <head>      <title></title>      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">      <script type="text/javascript"     src="https://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2">      </script>      <script type="text/javascript">          var map = null;          var LA = new VELatLong(35.644679, 139.734523);          var pinPoint = null;          var pinPixel = null;          var locationHistoryPolyLine = null;          var locationHistoryArray = new Array();          function GetMap() {              map = new VEMap('myMap');              map.LoadMap(LA, 14, VEMapStyle.Road, false, VEMapMode.Mode2D, true, 1);              AddPin();          }          function SetParams(lat, long, zoom) {              LA.Latitude = lat;              LA.Longitude = long;              map.LoadMap(LA, zoom, VEMapStyle.Road, false, VEMapMode.Mode2D, true, 1);              AddPin();          }      </script>   </head>   <body onload="GetMap();">      <div id='myMap' style="position:relative; width:400px; height:400px;"></div>       <input id="btnGetInfo" type="button"         value="Get Scene Information" name="getinfo" onclick="getInfo();">       <br/>      (zoom out 5 clicks to get latitude/longitude and zoom level)   </body></html>

このHTMLの中には、JavaScriptで記述されたBingMapを表示するためのfunctionやコードが記述されています。

プロジェクトにリソースとしてHTMLファイルを用意する場合には、Windowのロード時にHTMLファイルの中身をWebBrowserコントロールのNavigateToStringメソッドを使って流し込みます。

System.Reflection.Assembly current =    System.Reflection.Assembly.GetExecutingAssembly();string sourcePath = this.GetType().Namespace + ".BingMapCtrl.htm";System.IO.TextReader reader =    new System.IO.StreamReader(        current.GetManifestResourceStream(sourcePath));string htmlContent = reader.ReadToEnd();try{    webBrowser1.NavigateToString(htmlContent);}catch (Exception ex){    MessageBox.Show(ex.Message);}

これで、WPFアプリを実行すると、BingMapがWPFアプリとして表示されるはず。
WebBrowserコントロールには、InvokeScriptというメソッドが用意されていて、このメソッドを使って、WebBrowserコントロールにロードされているHTMLに記述された、JavaScriptのfunctionをコールすることができるんです。
例えば、こんな感じ。

string zoom = "14";webBrowser1.InvokeScript(    "SetParams",    new object[] {        location.Coordinate.Latitude,        location.Coordinate.Longitude,        zoom });

これで、HTMLファイルのSetParamsメソッドがコールされて、BingMapの表示の中心点が変わります。
TechDays2010のManagedのLocationライブラリに関するセッションでお見せしたデモは、こちらを使いました。GeoLocationProviderから取得した緯度経度情報を、InvokeScriptメソッドを通じて、JavaScriptのSetParamsをコールし、更に、そのfunctionの中で、BingMapsのAJAX Control APIを呼んであげればよいわけです。

AJAX Control APIでは、地図を3Dに切り替え(動かすPCにBingMaps 3D controlがインストールされている必要あり)ることもできます。APIを通じて、視点の方向や高さを変えることができるので、例えば3軸加速度センサーで、飛んでる感じのアプリを作るなんてことも、できるんです。

BingMaps AJAX APIの詳細は、https://www.microsoft.com/maps/isdk/ajax で紹介されているので、参考にしてくださいね。

…試にSensor Development Kitのボードで作ってみようと思ったのだが、直進/後進/左右旋回はすぐ思いつくけど、上昇下降の操作方法が思いつかないんだよねぇ。やっぱ脳波センサーで完全集中で月まで(って表示しないし)一っ跳びとか集中途切れて真っ逆さまに墜落?…