Bing Maps SearchService

30. Mai 2011

Einführung

In meinen vorherigen Blog-Beiträgen (Microsoft Bing Maps for Enterprise, BingMaps GeocodeService und BingMaps RouteService) zu dem Thema BingMaps, habe ich über die Darstellung von Punkten oder Routen auf einer BingMaps-Karte gesprochen. Im Gegensatz zu dem ersten Blog-Beitrag wurde bei den anderen die Webservices “GeocodeService” und “RouteService” mit eingebunden, die sich über die Webservices die Koordinaten der gesuchten Orte/Punkte holen bzw. die Route dazwischen berechnen.

Microsoft bietet aber 3 verschiedene WebServices für die Darstellung von Punkten, Linien oder Bereichen auf Karten an. Diese wären:

  1. GeocodeService (Punkte)
  2. RouteService (Punkte, Linien)
  3. SearchService (Punkte)

In diesem Blog Beitrag möchte ich die Verwendung des SearchService in BingMaps erläutern.

Wozu verwende ich den SearchService?

Mit Hilfe des SearchService wird eine Abfrage an den Webservice gestellt, der die Koordinaten (Längen- und Breitengrad im Format WGS84) der Adressen für einen bestimmten Suchbegriff (z.B. Pizza in Frankfurt) zurückliefert. Als Ergebnis erhält man eine Liste von Pizzerien in Frankfurt.

Der SearchService bietet sich besonders an, wenn man einen bestimmten Ort (z.B. die nächstgelegene Postfiliale) in seiner Nähe sucht.

Voraussetzungen

  • BingMaps-Key
  • Visual Studio
  • Silverlight

Falls Sie noch keinen BingMaps-Key haben, können Sie sich hier einen erstellen.

Silverlight-Applikation

Als erster Schritt wird eine neue Silverlight-Applikation erstellt und der SearchService als Service Reference hinzugefügt. Hierzu klicken Sie mit der rechten Maustaste auf das Projekt und wählen Add Service Reference. Geben Sie als Adresse http://dev.virtualearth.net/webservices/v1/SearchService/SearchService.svc ein und klicken auf Go. Nennen Sie den Namespace SearchService.

Im nächsten Schritt werden eine Textbox zum Eingeben der Suchparameter und ein Button zum Starten der Suche erstellt. Des Weiteren erstellen wir noch einen Textblock in dem wir ausgeben, wie viele Treffer gefunden wurden und eine Karte zum Darstellen der Suchergebnisse.

   1: <Grid x:Name="LayoutRoot" Background="White" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

   2:  <Grid.RowDefinitions>

   3:   <RowDefinition Height="auto"/>

   4:   <RowDefinition Height="*"/>

   5:  </Grid.RowDefinitions>

   6:  <StackPanel Grid.Row="0">

   7:   <TextBlock TextWrapping="Wrap"/>

   8:   <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" Margin="12,0,12,0">

   9:    <TextBox x:Name="strParameter" Width="500" KeyDown="strParameter_KeyDown" GotFocus="strParameter_GotFocus" HorizontalAlignment="Stretch"/>

  10:    <Button Content="Suchen" Click="Button_Click"/>

  11:    <TextBlock x:Name="outResults" Margin="14,0,0,0" VerticalAlignment="Center"/>

  12:   </StackPanel>

  13:  </StackPanel>

  14:  <map:Map Name="searchMap" CredentialsProvider="<Your Key>" Grid.Row="1">

  15:   <map:MapLayer x:Name="SearchResultLayer"/>

  16:   <map:MapLayer x:Name="ContentTooltipLayer">

  17:    <Canvas x:Name="ContentTooltip" Visibility="Collapsed" Opacity=".85" MouseEnter="ContentPopup_MouseEnter" MouseLeave="ContentPopup_MouseLeave">

  18:     <Rectangle x:Name="ContentTooltipRectangle" Fill="White" Canvas.Left="0" Height="100" Width="300" RadiusX="20" RadiusY="20"/>

  19:     <StackPanel Canvas.Left="10" Canvas.Top="10">

  20:      <TextBlock x:Name="ContentTooltipText"/>

  21:      <TextBlock x:Name="ContentTooltipDescription"/>

  22:     </StackPanel>

  23:    </Canvas>

  24:   </map:MapLayer>

  25:  </map:Map>

  26: </Grid>

In den nächsten beiden Methoden (ExecuteSearch und searchClient_searchCompleted) übergeben wir den Suchbegriff aus unserer Textbox an den Webservice. Dieser gibt eine Liste von Suchergebnissen zurück.

   1: private void ExecuteSearch(string query)

   2: {

   3:  //Set up the search request

   4:  SearchService.SearchServiceClient searchClient;

   5:  

   6:  // OutOfBrowser is currently supported on the MapControl only for http pages

   7:  bool httpsUriScheme = !Application.Current.IsRunningOutOfBrowser && HtmlPage.Document.DocumentUri.Scheme.Equals(Uri.UriSchemeHttps);

   8:  BasicHttpBinding binding = new BasicHttpBinding(httpsUriScheme ? BasicHttpSecurityMode.Transport : BasicHttpSecurityMode.None);

   9:  binding.MaxReceivedMessageSize = int.MaxValue;

  10:  binding.MaxBufferSize = int.MaxValue;

  11:  UriBuilder serviceUri = new UriBuilder("http://dev.virtualearth.net/webservices/v1/SearchService/SearchService.svc");

  12:  if (httpsUriScheme)

  13:  {

  14:   //For https, change the UriScheme to https and change it to use the default https port.

  15:   serviceUri.Scheme = Uri.UriSchemeHttps;

  16:   serviceUri.Port = -1;

  17:  }

  18:  

  19:  //Create the Service Client

  20:  searchClient = new SearchService.SearchServiceClient(binding, new EndpointAddress(serviceUri.Uri));

  21:  searchClient.SearchCompleted += new EventHandler<SearchService.SearchCompletedEventArgs>(searchClient_SearchCompleted);

  22:  

  23:  var request = new SearchService.SearchRequest

  24:  {

  25:   Culture = searchMap.Culture,

  26:   Query = query,

  27:   ExecutionOptions = new SearchService.ExecutionOptions { SuppressFaults = true }

  28:  };

  29:  

  30:  //Set up the Map View bounds for the request

  31:  LocationRect mapControlView = searchMap.BoundingRectangle;

  32:  

  33:  LocationRect mapBounds = new LocationRect(mapControlView);

  34:  request.UserProfile = new SearchService.UserProfile();

  35:  request.UserProfile.MapView = mapBounds;

  36:  

  37:  searchMap.CredentialsProvider.GetCredentials(

  38:    (Credentials credentials) =>

  39:  {

  40:   //Pass in credentials for web services call. Replace with your own Credentials.

  41:   request.Credentials = credentials;

  42:  

  43:   //execute the request

  44:   searchClient.SearchAsync(request);

  45:  });

  46: }

   1: private void searchClient_SearchCompleted(object sender, SearchService.SearchCompletedEventArgs e)

   2: {

   3:  string outputString;

   4:  try

   5:  {

   6:   if (e.Result.ResponseSummary.StatusCode == SearchService.ResponseStatusCode.Success)

   7:   {

   8:    outputString = string.Format(CultureInfo.InvariantCulture, "{0} Treffer", e.Result.ResultSets[0].Results.Count);

   9:    IList<Location> locations = new List<Location>();

  10:  

  11:    if ((e.Result != null) && (e.Result.ResultSets.Count > 0))

  12:    {

  13:     foreach (SearchService.SearchResultBase result in e.Result.ResultSets[0].Results)

  14:     {

  15:      searchResults.Add(result.Id, result);

  16:  

  17:      if (result.LocationData.Locations.Count > 0)

  18:      {

  19:       Location location = new Location(result.LocationData.Locations[0]);

  20:       //Create a pushpin

  21:       var pushpin = new Pushpin

  22:       {

  23:        Location = location,

  24:        Tag = result.Id

  25:       };

  26:  

  27:       SearchResultLayer.Children.Add(pushpin);

  28:       locations.Add(location);

  29:  

  30:       //Set up events for the pushpin

  31:       pushpin.MouseEnter += new MouseEventHandler(Pushpin_MouseEnter);

  32:       pushpin.MouseLeave += new MouseEventHandler(Pushpin_MouseLeave);

  33:  

  34:      }

  35:     }

  36:  

  37:     if (locations.Count > 0)

  38:     {

  39:      //If Search results were found, use the bounding area of the results

  40:      searchMap.SetView(new LocationRect(locations));

  41:     }

  42:     else

  43:     {

  44:      //Otherwise, if the SearchRegion is set from the service response, go ahead use that

  45:      LocationRect boundingArea = e.Result.ResultSets[0].SearchRegion.BoundingArea as LocationRect;

  46:      if (boundingArea != null)

  47:      {

  48:       searchMap.SetView(new LocationRect(boundingArea));

  49:      }

  50:     }

  51:    }

  52:   }

  53:   else

  54:   {

  55:    outputString = "error searching... status <" + e.Result.ResponseSummary.StatusCode.ToString() + ">";

  56:   }

  57:  }

  58:  catch (Exception)

  59:  {

  60:   outputString = "Exception Raised";

  61:  }

  62:  

  63:  outResults.Text = outputString;

  64: }

Damit wir auch wissen um wen es sich bei den Suchergebnissen handelt, erstellen wir noch zwei Events, die ausgeführt werden, wenn man einen Punkt mit der Maus berührt (Pushpin_MouseEnter) und wieder verlässt (Pushpin_MouseLeave). Beim Berühren eines Punktes mit der Maus sollen Informationen wie Name, Adresse und Telefonnummer in der Box angezeigt werden.

   1: void Pushpin_MouseLeave(object sender, MouseEventArgs e)

   2: {

   3:  //Hide the popup

   4:  UIElement content = sender as UIElement;

   5:  Canvas.SetZIndex(content, 100);

   6:  ContentTooltip.Visibility = Visibility.Collapsed;

   7: }

   8:  

   9: void Pushpin_MouseEnter(object sender, MouseEventArgs e)

  10: {

  11:  //Show the popup

  12:  Pushpin pushpin = sender as Pushpin;

  13:  Canvas.SetZIndex(pushpin, 500);

  14:  Point point = e.GetPosition(searchMap);

  15:  string resultId = pushpin.Tag as string;

  16:  SearchService.SearchResultBase searchResult = searchResults[resultId];

  17:  Location location = new Location(searchResult.LocationData.Locations[0].Latitude, searchResult.LocationData.Locations[0].Longitude);

  18:  MapLayer.SetPosition(ContentTooltip, location);

  19:  MapLayer.SetPositionOffset(ContentTooltip, new Point(25, -50));

  20:  

  21:  SearchService.SearchResultBase result = searchResults[resultId];

  22:  if (result != null)

  23:  {

  24:   ContentTooltipText.Text = result.Name;

  25:   SearchService.BusinessSearchResult businessResult = result as SearchService.BusinessSearchResult;

  26:   if (businessResult != null)

  27:   {

  28:    ContentTooltipDescription.Text = string.Format("{0}
{1}
", businessResult.Address.FormattedAddress, businessResult.PhoneNumber);

  29:   }

  30:   ContentTooltip.Visibility = Visibility.Visible;

  31:  }

  32: }

  33:  

  34: private void ContentPopup_MouseEnter(object sender, MouseEventArgs e)

  35: {

  36:  //Show the popup if mouse is hovering over it

  37:  ContentTooltip.Visibility = Visibility.Visible;

  38:  Canvas.SetZIndex(ContentTooltip, 10);

  39: }

  40:  

  41: private void ContentPopup_MouseLeave(object sender, MouseEventArgs e)

  42: {

  43:  //Hide the popup if mouse leaves it

  44:  ContentTooltip.Visibility = Visibility.Collapsed;

  45: }

Zum Schluss müssen wir noch eine Methode zum Ausführen der Suche erstellen, die ausgeführt wird, wenn der Button gedrückt wird.

   1: private void strParameter_KeyDown(object sender, KeyEventArgs e)

   2: {

   3:  if (e.Key == Key.Enter)

   4:  {

   5:   StartSearch();

   6:  }

   7: }

   8:  

   9: private void strParameter_GotFocus(object sender, RoutedEventArgs e)

  10: {

  11:  strParameter.SelectAll();

  12: }

  13:  

  14: private void Button_Click(object sender, RoutedEventArgs e)

  15: {

  16:  StartSearch();

  17: }

  18:  

  19: private void StartSearch()

  20: {

  21:  ClearSearch();

  22:  

  23:  searchMap.Focus();

  24:  

  25:  string query = strParameter.Text;

  26:  if (!string.IsNullOrEmpty(query))

  27:  {

  28:   ExecuteSearch(query);

  29:  }

  30: }

  31:  

  32: private void ClearSearch()

  33: {

  34:  foreach (UIElement pin in SearchResultLayer.Children)

  35:  {

  36:   pin.MouseEnter -= Pushpin_MouseEnter;

  37:   pin.MouseLeave -= Pushpin_MouseLeave;

  38:  }

  39:  

  40:  SearchResultLayer.Children.Clear();

  41:  searchResults.Clear();

  42: }

Ergebnis

Starten Sie nun die Solution und geben einen Suchbegriff ein. Klicken Sie anschließend auf Suchen um den SearchService anzusprechen.

image

Gesamtfazit

Abschließend kann man sagen, dass die unterschiedlichen Services (GeocodeService, RouteService und SearchService), die ich in dieser BlogSerie beschrieben habe, eine gute Ergänzung für die Entwicklung von BingMaps-Applikation sind.

Durch das frei verfügbare Bing Maps Silverlight Control SDK und Bing Maps Silverlight Control Interactive SDK werden dem Entwickler hilfreiche Tipps und Beispiele zur Verfügung gestellt.

BingMaps bietet mit den Services Unternehmen in den unterschiedlichsten Branchen eine gute Möglichkeit seine Daten geovisualisiert darzustellen. Durch die Sicht auf die geographische Lage können die Daten auf eine weitere Art analysiert werden.

Insbesondere der GeocodeService bietet dem Unternehmen eine gute Hilfe für die geovisualisierte Analyse seiner Daten.