はじめに
前回に引き続いて今回もBing Map App SDKの紹介です。前回はごく簡単なアプリケーションを作り、実行方法を紹介しました。今回は新たにBing Map Appの次の機能を紹介します。
今回作成するMap Appは、図1のように県庁所在地の場所にプッシュピンを表示する単純なものですが、左側のパネルを活用しています。パネル内の地名をクリックするとその場所へ移動します。
プラグイン クラスの作成
最初にMap Appのプロジェクトおよびプラグイン クラスを作りましょう。前回と同様ですので、前回の内容を参照しながら作成してください。
プロジェクトはC#のSilverlightクラス ライブラリ プロジェクトです。プロジェクト作成後、Bing Map App SDKのライブラリーの参照の追加をしてください。今回はプロジェクト名をCapitalCitiesBingMapAppとしました。
続いて、Pluginクラスを継承したクラスを作ります。またContractのImportも行います。クラス名はCapitalCitiesPlugin、ファイル名はCapitalCitiesPlugin.csとしました。コードは次のようになります。Initializeメソッドの内容は後から編集します。
エンティティの作成
エンティティとはプッシュピンなどの地図上に表示するアイテムでした。前回のコードでは、Initializeメソッド内で直接、Entityクラスそのものを生成して使用していましたが、今回はEntityクラスを継承して、県庁所在地を表すエンティティ クラスを作成して使用します。といっても県庁所在地の名前を設定するプロパティを追加しただけの簡単なものです。
プロジェクトに新しいクラスを追加して、次のようにコードを記述します。ファイル名はCityEntity.cs、クラス名はCityEntityとします。
レイヤーの作成
続いてレイヤーを作成しましょう。レイヤーには県庁所在地を示すエンティティを追加します。また、レイヤーにはパネルも追加します。まずは、エンティティを追加する処理を書きましょう。
前回のコードではエンティティの追加を、プラグイン クラスのInitializeメソッドで行っていましたが、今回はレイヤーのコンストラクタ内で行います。
XMLファイルの追加
県庁所在地の名前と経緯度情報は、情報を記載したXMLファイルを用意して、ここから情報を取得するようにしましょう。プロジェクトにリソースとして追加して、レイヤーのコンストラクタ処理のときに読み込みエンティティを作成することにします。
プロジェクトに新しい項目としてXMLファイルを追加します(図2)。ファイル名はCities.xmlとします。追加後、ソリューションエクスプローラからファイルを選択して、ビルドアクション
プロパティを「埋め込まれたリソース」に設定します(図3)。
XMLファイルの内容は次のように、47都道府県分の<Pushpin>要素を記述して、属性として地名と経緯度の値を設定します。
以上でXMLファイルの準備は完了です。内容からわかるように別に県庁所在地である必要はなく、好きな地名と経緯度を記述して構いません。
レイヤークラスの作成
次にLayerクラスを継承したレイヤー クラスを作成します。プロジェクトに新しいクラスを追加します。クラス名はCityLayer、ファイル名はCityLayer.csにします。
コンストラクタ内でXMLファイルを読み込み、その値からCityEntityオブジェクトを生成し、レイヤーに追加していく処理は次のようになります。プッシュピンの生成もここで行っています。
このレイヤーはプラグイン クラスから生成されることを想定しています。また、内部でプッシュピンの作成などを行うため、プラグインの参照をコンストラクタ引数で受け取り、プラグインの持つContractを使用できるようにしています。
このレイヤーを生成するコードをプラグインのInitializeメソッドに記述しておきましょう。
パネルの作成
それでは、パネルを作成してみましょう。パネルは、ユーザー コントロールとして作成します。プロジェクトにSilverlightユーザー コントロールを追加します(図4)。ファイル名は、CityPanel.xamlとしました。
追加したUserControlのXAMLを編集して、<Grid>要素内に次のコードを追加します。
XAML内の「SelectionChanged="ListBox_SelectionChanged"」部分は、リストボックスの選択が変更されたイベントの時に呼ぶメソッド名を指定しています。すべて自分で記述せず、Visual Studioの機能を利用してイベント処理を追加します。 プロパティウィンドウからイベントタブを選択して「SelectionChanged」の項目に「ListBox_SelectionChanged」を設定する(図5)と、CityPanel.xaml.csにイベント処理のコードが自動で生成されます。
CityPanel.xaml.csのコードは次のように編集します。ItemMouseClickedというイベントを定義して、パネルで地名を選択したときにイベントが発生するようにしています。
以上で、パネル自体の記述は完成です。
レイヤーはひとつのパネルを持つことが可能です。ここで作成したパネルは、作成済みのCityLayerクラスで生成し、レイヤーのパネルとして設定します。CityLayerのコンストラクタの処理の最後に次のコードを追記します。
CityPanelのDataContextプロパティにレイヤーのエンティティのコレクションを指定し、パネル上に県庁所在地の情報を表示できるようにしています。また、ここではレイヤーのTitleプロパティも合わせて設定しています。Titleプロパティに設定した値は図1のようにパネル上部に表示されます。
上記コードのパネルの項目をクリックしたときの処理も記述しましょう。クラス内に次のメソッドを追記します。
項目をクリックすると、その県庁所在地の場所まで地図を移動させます。プラグインのMapContract型のDefaultMapプロパティを使ってSetViewメソッドにより指定した場所へ移動させています。
以上で、県庁所在地にプッシュピンを表示し、パネルから移動が可能なMap Appができました。ビルドして実行してみましょう。実行方法は前回の内容を参照してください。うまく動いたでしょうか?
レイヤーのシリアライズ
ここでレイヤーのシリアライズについて紹介しておきます。今回作成したMap Appを実行して、ある県庁所在地に移動していたとします。その状態から、検索ボックスにどこか別の場所を入力して移動します。このときWebブラウザーの戻るボタンをクリックしてみると、直前に表示していた地図の状態には戻りません。ユーザーが期待した動作(直前に表示していた状態に戻る)とは異なってしまいます。期待した動作にするために、レイヤーのシリアライズを行います。
ここでのシリアライズとは、ある状態を保持しているオブジェクトを、文字列などの情報に変換することです。変換するとファイルなどに保存が可能になります。そして必要なときに、変換・保存した情報からある状態のオブジェクトを再度生成します。この元に戻すことをデシリアライズと呼びます。
つまり、ここではレイヤーの持っている情報をシリアライズし、またWebブラウザーの戻るボタンなどにより再度表示を行いたいタイミングでデシリアライズを行い、レイヤーを復元します。
レイヤーのシリアライズは、SerializationContractというContractを使用します。これまで紹介したContractはImportして提供される機能をプラグインから利用していましたが、それらとは異なり、プラグインの提供する機能としてExportします。CapitalCitiesPluginクラスに次のプロパティを追加します。
プラグインは機能を提供側ですので、その機能を実装します。SerializationContract<Layer>クラスを継承したクラスを作成し、シリアライズとデシリアライズ機能を記述します。プロジェクトに、LayerSerializationContractという名前のクラスを追加して次のように記述します。
コードの内容はいたって簡単です。コンストラクタでは、シリアライズ・デシリアライズを行うレイヤーオブジェクトを引数として受け取ります。Serializeメソッド、Deserializeメソッドではそれぞれ、受け取ったレイヤーに対してシリアライズ・デシリアライズを行います。戻り値や引数からもわかるように、レイヤー情報は文字列のキーと値の組み合わせのコレクションに変換します。
上記コードでは、シリアライズ・デシリアライズ処理を特に何もしていません。実は、今回のアプリケーション程度の、プッシュピンの位置や地図の表示位置はライブラリーで対処してくれるようです。独自にレイヤーに対して情報を設定している場合は、シリアライズ・デシリアライズ処理が必要になってきます。
最後に、プラグインのLayerSerializationContractプロパティにLayerSerializationContractクラスのオブジェクトを設定するコードを書きましょう。Initializeメソッドの内容を次のように編集します。
以上でBing MapがこのMap Appのシリアライズ・デシリアライズ機能が使用できるようになりました。次の手順で動作を確認してみましょう。
- Map Appを実行する
- 検索ボックスに地名を入力し、その場所へ移動する
- Webブラウザーの戻るボタンをクリックする
シリアライズ・デシリアライズ処理した場合と、していない場合と比較してみてください。きちんとシリアライズ・デシリアライズ処理は動作したでしょうか?
ちなみに、Map App実行時に最初はInitializeメソッド、Activateメソッドの順で呼ばれますが、デシリアライズ処理がされる場合、Activateメソッドは呼ばれません。
いかがでしたでしょうか。今回も簡単なアプリケーションを作成してみました。まだまだMap Appとして作りこむ要素が残っています。次回もMap Appの作成について紹介します。