"Desktop Map App Development" SeriesPart7.
This time,Part6 map app created in the previous installment will be enhanced with an address search feature. Sample code for the features introduced in this article is available on Esri Japan GitHub .
Address Search
ArcGIS Maps SDK for .NET provides geocoding functionality to obtain locations from text address strings, and reverse geocoding to get addresses from specific locations. This time, we will implement a feature that zooms the map to the location corresponding to the address entered in a text box.Geocoding
1. In MapViewModel.cs,create a new property calledGraphicsOverlays.This is a collection of GraphicsOverlay objects that store graphics for address search results (symbols for address locations and labels for address strings).
MapViewModel.cs
private GraphicsOverlayCollection? _graphicsOverlays;
public GraphicsOverlayCollection? GraphicsOverlays
{
get { return _graphicsOverlays; }
set
{
_graphicsOverlays = value;
OnPropertyChanged();
}
}
2. Open MainWindow.xaml and use data binding to bind the GraphicsOverlays property of MapViewModel to the MapView control (add GraphicsOverlays="{Binding GraphicsOverlays, Source={StaticResource MapViewModel}}" ).
MainWindow.xaml
<esri:MapView x:Name="MainMapView"
Map="{Binding Map, Source={StaticResource MapViewModel}}"
GraphicsOverlays="{Binding GraphicsOverlays, Source={StaticResource MapViewModel}}"
GeoViewTapped="MainMapView_GeoViewTapped"/>
3. In MapViewModel.cs, add code to the SetupMap function to create a new
{
geocodeResultOverlay
};
this.GraphicsOverlays = graphicsOverlays;
// 住所検索用の LocatorTask を作成する
Uri _serviceUri = new Uri("https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer");
_geocoder = await LocatorTask.CreateAsync(_serviceUri);
}
4. MainWindow.xaml で住所を入力するテキスト ボックスを含んだ画面を作成します。
MainWindow.xaml
<Border HorizontalAlignment="Right" VerticalAlignment="Top" Background="White" BorderThickness="0.5" BorderBrush="Gray" Margin="10" Padding="10" Width="250">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" FontWeight="SemiBold" Text="住所を入力" TextAlignment="Center" />
<TextBox x:Name="SearchBox" Grid.Row="1" Grid.Column="0" Margin="0,5,5,0" Text="東京都千代田区平河町2-7-1"/>
<Button x:Name="SearchButton" Grid.Row="1" Grid.Column="1" Margin="0,5,0,0" Click="SearchButton_Click" Content="検索"/>
</Grid>
</Border>
5. MainWindow.xaml.cs に検索ボタンをクリックした時の処理を実装します。
MainWindow.xaml.cs
// 住所検索ボタンのクリック イベント ハンドラー
private async void SearchButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
var currentMapViewModel = (MapViewModel)this.FindResource("MapViewModel");
// テキストボックスの値を取得して、住所検索を実行する
MapPoint? addressPoint = await currentMapViewModel.SearchAddress(SearchBox.Text);
if (addressPoint != null) {
// 検索した住所にマップの表示位置を変更する
MainMapView.SetViewpoint(new Viewpoint(addressPoint, 20000));
}
}
6. MapViewModel.cs に住所検索の処理を実装します。ジオコーディングを実行する GeocodeAsync メソッドには、オプションで検索結果を細かく指定するためのパラメーター(GeocodeParameters)を設定できます。GeocodeAsync メソッドは、デフォルトで検索結果の候補の住所全て(最大50個まで)が、マッチ率が高い順で返されます。今回は、MaxResults プロパティを設定し検索結果として返される候補の住所を1個に制限しています。検索結果で返される情報の詳細については、こちらも併せてご参照ください。
MapViewModel.cs
public async Task<MapPoint> SearchAddress(string searchText)
{
MapPoint? addressLocation = null;
try {
// 既存の検索結果のグラフィックスを消去する
GraphicsOverlay? geocodeResultOverlay = this.GraphicsOverlays?.FirstOrDefault();
geocodeResultOverlay!.Graphics.Clear();
// テキストボックスの値が空か LocatorTask が無効の場合は、処理を中止する
if (String.IsNullOrWhiteSpace(searchText) || _geocoder == null) {
throw new Exception("検索文字列が空か、ジオコーダーが無効です");
}
// 検索結果を1つ(マッチ率が最も高い住所)だけに制限する、ジオコーディングのパラメーターを作成する
GeocodeParameters geocodeParameters = new GeocodeParameters();
geocodeParameters.MaxResults = 1;
//入力文字列からジオコーディングを実行しマッチする住所(住所文字列と位置)を取得する
IReadOnlyList<GeocodeResult> addresses = await _geocoder.GeocodeAsync(searchText, geocodeParameters);
// 検索結果が取得できない場合は処理を中止する
if (addresses.Count < 1) {
throw new Exception("一致する結果がありません");
}
// 住所の位置に表示するポイント シンボルを作成する
SimpleMarkerSymbol pointSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Diamond, System.Drawing.Color.Red, 15);
// 住所文字列のテキスト シンボルを作成する
TextSymbol textSymbol = new TextSymbol(addresses.First().Label, System.Drawing.Color.Yellow, 15, Esri.ArcGISRuntime.Symbology.HorizontalAlignment.Center, Esri.ArcGISRuntime.Symbology.VerticalAlignment.Bottom);
textSymbol.HaloColor = System.Drawing.Color.Gray;
textSymbol.HaloWidth = 3;
textSymbol.OffsetY = 10;
// ポイントとテキスト シンボルからグラフィックを作成する
Graphic pointGraphic = new Graphic(addresses.First().DisplayLocation, pointSymbol);
Graphic textGraphic = new Graphic(addresses.First().DisplayLocation, textSymbol);
// GraphicsOverlay にグラフィックを追加する
geocodeResultOverlay.Graphics.Add(pointGraphic);
geocodeResultOverlay.Graphics.Add(textGraphic);
// マップを住所の位置にズームするためのポイントを返す
addressLocation = addresses.First().DisplayLocation;
}
catch (Exception ex) {
MessageBox.Show(ex.ToString(), "エラー");
}
return addressLocation!;
}
7. アプリを実行してみましょう。入力した住所にマップが移動し、住所テキストとシンボルがマップ上に表示されます。
第7弾「住所検索」では住所文字列から該当する位置を取得するジオコーディングの機能を実装する方法を紹介しました。次回、第8弾では概観図の作成方法を紹介します。
関連リンク