※本記事は、連載記事「.NET SDK アプリ構築」の第 6 回目の記事です。
前回(第5回)の記事では、ArcGIS for Developers にアプリケーション情報を登録し、ArcGIS Online に公開したサービスにアクセスするための認証情報をサンプル アプリケーションに埋め込む手順や、実際にフィーチャ サービスをレイヤーとしてサンプル アプリケーションに追加する手順をご紹介しました。今回は、追加したフィーチャ サービスの属性情報をマップチップ(地図上に表示されるポップアップ情報)として表示する方法についてご紹介します。

マップチップの実装方法
マップチップの表示は MapView コントロールの Overlays プロパティを使用します。
マップビュー オーバーレイは、マップ上の最上位の要素として扱われ、ユーザーがクリックした際にフィーチャの属性情報を表示したり、マップ上で強調表示したい場所やフィーチャのラベルを表示したりする際に使用します。マップチップを実装する際には、以下のように XAML 内の MapView コントロールに MapView.Overlays の要素を追加します。
[MainWindow.xaml]
<esri:MapView x:Name="myMapView"> <esri:Map> <esri:ArcGISTiledMapServiceLayer ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer " /> </esri:Map> <esri:MapView.Overlays> <esri:OverlayItemsControl> <!-- UI 定義と表示するデータの設定 --> </esri:OverlayItemsControl> </esri:MapView.Overlays> </esri:MapView>
サンプルアプリケーションへのマップチップの追加
ここからは、地図上に表示される物件にマウス カーソルをホバーした際に、物件の属性情報をマップチップで表示する手順をサンプル アプリケーションのソースコードの Step_6 プロジェクトを参照しながら紹介していきます。
まずは MainWindow.xaml に以下の実装を行います。
- マウス移動イベント ハンドラの追加
- マップビュー オーバーレイ の追加
- マップチップ UI の定義
- 属性情報のバインディング
1:マウス移動イベント ハンドラの追加
MainWindow.xaml でマップビュー(名前:mainMapView)上でマウスを移動した際に発生する MapView.MouseMove イベントのイベント ハンドラ( mainMapView_MouseMove)を追加します(この時、MainWindow.xaml.cs にも自動的に mainMapView_MouseMove イベント ハンドラの実装が追加されます)。
[MainWindow.xaml]
<!--マップビュー--> <esri:MapView Grid.Column="1" x:Name="mainMapView" Loaded="mainMapView_Loaded" MouseMove="mainMapView_MouseMove">
2:マップビュー オーバーレイの追加
ポップアップを表示するためにマップビューに Overlays プロパティを定義し、子要素として OverlayItemsControl コントロールを追加します。
[MainWindow.xaml]
<!--マップビューオーバーレイ--> <esri:MapView.Overlays> <esri:OverlayItemsControl>
3:マップチップ UI の定義
表示するマップチップの UI を定義します。マップチップの外枠を Border クラス(名前:mapTip)で定義します。Border クラスの子要素として Grid クラスを追加し、ColumDefinitions および RowDefinitions プロパティを使用して、属性情報を表示するためにグリッドを縦横に分割します。マップチップはアプリケーションの起動時には非表示とするため、Border クラスをの Visibility プロパティを Collapsed に設定して非表示にします。
[MainWindow.xaml]
<!--マップチップ--> <Border Grid.Column="1" x:Name="mapTip" Background="White" BorderBrush="Black" BorderThickness="2" Padding="4" VerticalAlignment="Top" HorizontalAlignment="Right" Visibility="Collapsed"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="50" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> <RowDefinition /> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions>
4:属性情報のバインディング
先程の手順で追加した Grid クラスの子要素として物件の属性情報のラベルと値を表示するための TextBlock クラスを追加します。Grid.Row および Grid.Column 添付プロパティを使用して分割された Grid の適切な位置に TextBlock を配置します。属性情報のラベルを表示するための TextBlock の Text プロパティにはそれぞれテキストとして「名前:」、「住所:」、「部屋数:」、「築年数:」、「構造:」、および「駐車場:」を設定します(築年数の行のみ単位の「年」を表示する TextBlock も追加しています)。
[MainWindow.xaml]
<TextBlock Text="名前: " HorizontalAlignment="Right" /> <TextBlock Grid.Column="1" Text="{Binding Attributes[BuildingName], Mode=OneTime}" /> <TextBlock Grid.Row="1" Text="住所: " HorizontalAlignment="Right" /> <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Attributes[Address], Mode=OneTime}" /> <TextBlock Grid.Row="2" Text="部屋数: " HorizontalAlignment="Right" /> <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Attributes[NumberOfRooms], Mode=OneTime}" /> <TextBlock Grid.Row="3" Text="築年数: " HorizontalAlignment="Right" /> <StackPanel Grid.Row="3" Grid.Column="1" Orientation="Horizontal"> <TextBlock Text="{Binding Attributes[Age], Mode=OneTime}" /> <TextBlock Text="年" /> </StackPanel> <TextBlock Grid.Row="4" Text="構造: " HorizontalAlignment="Right" /> <TextBlock Grid.Row="4" Grid.Column="1" Text="{Binding Attributes[Structure], Mode=OneTime}" /> <TextBlock Grid.Row="5" Text="駐車場: " HorizontalAlignment="Right" /> <TextBlock Grid.Row="5" Grid.Column="1" Text="{Binding Attributes[Parking], Mode=OneTime}" /> </Grid>[マップチップの UI]

属性情報の値を表示するための TextBlock クラスの Text プロパティには、物件データのフィーチャ サービスから取得する物件レコード(Feature クラス)の Attributes プロパティに含まれる各属性列([BuildingName (建物名)]、[Address (住所)]、[NumberOfRooms (部屋数)]、[Age (築年数)]、[Structure (構造)] および [Parking (駐車場)]) の値をそれぞれバインドします。フィーチャ サービスから取得する Feature の Attributes プロパティの各属性列の名前は、物件データのフィーチャ サービスの REST エンドポイントのページ内の「Fields:」セクションで確認することができます。

※ REST エンドポイントの表示方法は第 4 回を参照してください。
物件レコード(Feature クラス)の Attributes プロパティに含まれる各属性列の値を TextBlock の Text プロパティにバインドする場合、以下の構文で値へのパスを指定します。
Text="{Binding Attributes[フィールド名], Mode=OneTime}"
例えば物件の部屋数(NumberOfRooms)をバインドする場合は以下のようになります。
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Attributes[NumberOfRooms], Mode=OneTime}" />上記のように指定をしておけば、TextBolck もしくは TextBlock の親要素の DataContext プロパティに物件レコード(Feature クラス)が設定されると Feature クラスの Attributes プロパティの指定された属性列(上記の例では NumberOfRooms)の値が TextBolck の Text プロパティにバインドされます。マップチップの表示では、表示中にバインドされた値が変更されることはないため、バインディングのモードを OneTime としています。
続いて、MainWindow.xaml.cs に対して以下の実装を行います。
- メンバ変数(フィールド)の定義
- 物件レイヤーのヒットテスト実行可否の制御
- マウス カーソル位置の取得
- マウス カーソル位置に物件が存在するかの確認
- 対象物件の取得
- マップチップの DataContext プロパティの設定と表示設定
1:メンバ変数(フィールド)の定義
MainWindow.xaml.cs にフィーチャ レイヤーへのヒットテスト中であるかどうかを示す bool 型のメンバ変数(フィールド)を定義します。
[MainWindow.xaml.cs]
private bool isHitTesting; //フィーチャレイヤへのヒットテスト中であるかどうかを示す変数
2:物件レイヤーのヒットテスト実行可否の制御
マウス移動イベントのハンドラ(mainMapView_MouseMove)内に「メンバ変数の定義」のステップで定義したフィーチャ レイヤーへのヒットテスト中であるかどうかを示す bool 型の変数(isHitTesting)を使用して、物件レイヤーへのヒットテストが重複して実行されないように制御します(同様にマップが準備中の場合もヒットテストを行わないように isMapReady メンバ変数を使用して制御しています)。
[MainWindow.xaml.cs]
//マップが準備できていなければ処理を行わない if (!isMapReady) return; //物件レイヤのヒットテスト中は処理を行わない if (isHitTesting) return;
3:マウス カーソル位置の取得
マウス移動イベント ハンドラ(mainMapView_MouseMove)内に try-catch-finally ステートメントを追加します。try ステートメント内には、マップビューに対するマウス カーソルの位置を取得するコードを追加します。マウス カーソルの位置(変数名:screenPoint)は、MapView の MouseMove イベントが返す MouseEventArgs の GetPosition メソッドで取得します。catch ステートメント内には、エラーを示すコードと、マップチップを非表示にするコードを追加します。最後に、finally ステートメント内には、物件レイヤーへのヒットテストの処理が終了したことを示すために isHitTesting 変数を false に設定するコードをそれぞれ追加します。
[MainWindow.xaml.cs]
try { //マップビューに対するマウス カーソル位置を取得 System.Windows.Point screenPoint = e.GetPosition(mainMapView); } //エラーが発生した場合の処理 catch (Exception ex) { MessageBox.Show(string.Format("マップチップの非表示:{0}", ex.Message)); //マップチップを非表示 mapTip.Visibility = System.Windows.Visibility.Collapsed; } finally { //物件レイヤへのヒットテスト終了 isHitTesting = false; }4:マウス カーソル位置に物件が存在するかの確認
マウス カーソルの位置に物件レイヤー(変数名:buildingLayer)に追加されている物件が存在するかどうかの確認を FeatureLayer.HitTestAsync メソッドを使用して実行します。HitTestAsync メソッドの引数には、マップビュー(名前:mainMapView)および、「マウス カーソル位置の取得」の手順で取得したマウス カーソルの位置(変数名:screenPoint)を指定します。HitTestAsync メソッドは非同期メソッドのため、「async」および「await」キーワードが必要となります。HitTestAsync メソッドはマウス カーソルの位置に存在する物件フィーチャの ObjectID (フィーチャ サービスに存在するフィーチャを一意に識別するための ID)を long 型の配列として返します。
[MainWindow.xaml.cs]
try { //マップビューに対するマウス カーソル位置を取得 [略] //マウス カーソルの位置に物件フィーチャが存在するかヒットテストを実行 long[] objectIds = await buildingLayer.HitTestAsync(mainMapView, screenPoint); }5:対象物件の取得
HitTestAsync メソッドを使用して取得した ObjectID の配列を使用してマウス カーソルの位置に存在する物件(Feature クラス)を取得します。物件レイヤー(buildingLayer) の属性テーブルである FeatureTable プロパティ(ServiceFeatureTable)の QueryAsync メソッドを使用して、取得した ObjectID を持つフィーチャを取得します。QueryAsync メソッドは指定された ObjectID の配列と一致するすべてのフィーチャを返します。今回のコードでは最初に返される物件を結果(変数名:feature)として取得します。また、マウス カーソルの位置に物件フィーチャが存在しなかった場合にはマップチップを非表示とします。
[MainWindow.xaml.cs]
try { //マップビューに対するマウス カーソル位置を取得 [略] //マウス カーソルの位置に物件フィーチャが存在する場合はマップチップを表示 if (objectIds != null && objectIds.Length > 0) { //ヒットテストが返したObject ID を持つ物件フィーチャを取得 IEnumerable<Feature> features = await buildingLayer.FeatureTable.QueryAsync(objectIds); Feature feature = features.FirstOrDefault(); } else { //マップチップを非表示 mapTip.Visibility = System.Windows.Visibility.Collapsed; } }6:マップチップの DataContext プロパティの設定と表示設定
「グリッド定義」の手順で定義したマップチップの DataContext プロパティに取得した物件フィーチャ(変数名:feature)を設定します。次に、マップチップの表示位置をマウス カーソルの位置に移動し、非表示になっていたマップチップを表示に切り替えます。
[MainWindow.xaml.cs]
try { //マップビューに対するマウス カーソル位置を取得 [略] //マウス カーソルの位置に物件フィーチャが存在する場合はマップチップを表示 if (objectIds != null && objectIds.Length > 0) { //マップチップのデータコンテキストに物件フィーチャを設定 [略] mapTip.DataContext = feature; //マップチップの表示位置をマウス カーソルの位置に設定 MapPoint anchorPoint = mainMapView.ScreenToLocation(screenPoint); MapView.SetViewOverlayAnchor(mapTip, anchorPoint); //マップチップを表示 mapTip.Visibility = System.Windows.Visibility.Visible; } }以上で、地図上に表示される物件の属性情報をマップチップとして表示するための実装は完了です。
サンプルアプリケーションへの実行
実装を行ったサンプル アプリケーションを実行し、任意の建物にマウス カーソルを移動することで、建物の名前や住所といった属性情報がマップチップとして表示されることを確認します。

本記事では、フィーチャ サービスの属性情報をマップチップとして表示する手順を紹介しました。第 7 回の記事では、マップに表示する物件フィーチャをフィルタリングする手順を紹介します。
関連リンク
ArcGIS Runtime SDK for .NET サンプル アプリ構築:
ESRIジャパン Web サイト:
Esri 社(米国) Web サイト: