Il presente articolo è stato tradotto automaticamente.

Applicazioni Bing Maps

Creazione di un’applicazione con transiti in tempo reale mediante il Bing Map App SDK

Luan Nguyen

Scaricare il codice di esempio

Durante la conferenza Tech•ed 2010 di giugno, Microsoft ha annunciato la disponibilità di libero Bing mappa App SDK, che consente agli sviluppatori di scrivere le applicazioni incentrate sui mapping di mappe Bing esplorare il sito all'indirizzo bing.com/maps/explore /.

Ciò presenta ample opportunità per le organizzazioni, aziende o appassionati di creare le proprie esperienze di mapping in mappe Bing.Le aziende possono scrivere applicazioni per pubblicizzare prodotti o per integrare i servizi in linea.Bestparking.com , ad esempio, ha sviluppato un'applicazione “ parcheggi finder ”, che consente di trovare tutte le strutture di parcheggio nella tua città utilizzando i relativi database.

Per visualizzare l'aspetto di un'applicazione mappa, andare a carte Bing esplorare il sito e fare clic sul pulsante MAP APPS vicini all'angolo inferiore sinistro della pagina.Verrà aperta la raccolta di applicazioni mappa con le applicazioni disponibili.Esistono già molte applicazioni disponibili nella raccolta e continua a crescere.

In questo articolo descriverò le operazioni necessarie per scrivere un'applicazione mappa utilizzando il SDK di Bing mapping applicazioni.Verrà consentono lo sviluppo di un'applicazione di esempio che mostra informazioni di arrivo bus in tempo reale intorno King County nello stato di Washington.Questa applicazione è ispirata all'applicazione a un bus esterno comune.

Il prodotto finale

Prima approfondire il codice, let’s dare un'occhiata all'aspetto dell'applicazione mappa finale.Quando attivato, se la mappa viene ingrandita nell'area di King County, applicazione mappa verrà visualizzata nel riquadro sinistro l'elenco di tutti i punti di bus all'interno del riquadro di visualizzazione mappa (vedere di Figura 1).

image: The OBA App Shows Bus Information on the Left Panel and Pushpins on the Map

Figura 1 di The Information Bus Mostra applicazioni OBA nel Pannello a sinistra e la mappa di simboli

Ogni interruzione del bus dispone di informazioni su tutti i bus che gestiscono tale interruzione.Per visualizzare il Pannello secondo, che visualizza l'ora di arrivo imminente (vedere di Figura 2) fare clic sul collegamento ipertestuale per ogni interruzione “ arrivo volte ”.

image: Bus Arrival Times for a Particular Bus Stop

Figura 2 di bus arrivo ore per un particolare blocco di Bus

L'applicazione inoltre colloca un simbolo visivo (contrassegnato con la lettera B) a ogni arresto bus sulla mappa.È possibile interagire con i simboli per attivare una finestra popup da cui è possibile richiamare comandi comuni per un particolare interruzione bus, ad esempio recupero driving o scorrere le direzioni a o (vedere di Figura 3) da esso.

image: Clicking on a Pushpin Shows a Pop-Up UI with Extra Information

Figura 3 clic su un simbolo Visualizza un'interfaccia utente popup con informazioni extra

Scaricare il SDK di Bing mapping applicazioni

Prima di iniziare a scrivere la prima applicazione mappa, è necessario installare il SDK di applicazione mappa Bing in connect.microsoft.com/bingmapapps .il SDK fornisce l'assembly di riferimento, un progetto di esempio e documentazione in linea.Inoltre, poiché il SDK è basato su Silverlight 4, inoltre occorre installare 4 Silverlight Tools per Visual Studio 2010, disponibile all'indirizzo silverlight.net/getstarted/ .

Nozioni fondamentali di mapping applicazioni

Esplorare le mappe Bing sito è stato realizzato con estensibilità come una delle priorità principali.Il team Bing mappe desiderava consentono agli sviluppatori di tutto il mondo aggiungere facilmente funzionalità potrebbe risultare utile e che potrebbe essere potenzialmente utile agli altri.In that sense, a map app is a concrete feature that makes use of the building block services provided by the core of Bing Maps.Se si osserva il sito Bing mapping predefinito, stradali, funzionalità business percorso di ricerca e ricerca tutti generate dai blocchi stessi.

Tenendo presente tale obiettivo, il team Bing mappe ha deciso di creare un framework estendibile per supportare il concetto di mapping applicazioni.Quando viene scritta su framework, mapping applicazioni usufruire di un approccio di tipo injection dipendenza per fornire accesso alle funzionalità analoghe a quelle disponibili in MEF (Managed Extensibility Framework).

Alla base del framework è il concetto di plug-in.Un plug-in è un'unità di estendibilità che consente agli sviluppatori di aggiungere funzionalità in modo gestibile e separato.Può essere considerato come l'equivalente di una parte della terminologia MEF componibile.Tramite gli attributi, un plug-in dichiara importazioni che deve nonché esportazioni da condividere.In fase di esecuzione, il framework verrà risolve le dipendenze tra i plug-in e soddisfano le importazioni con le esportazioni del contratto stesso.

Per scrivere un'applicazione mappa, è possibile creare una libreria di classi Silverlight 4 contiene esattamente una sottoclasse della classe base del plug-in.Per eseguire operazioni utili, il plug-in verrà probabilmente importare un numero di contratti incorporati che consentono di accedere a vari servizi di base.La documentazione SDK include una sezione in cui sono elencati tutti i contratti incorporati esportati dal framework.

Per fare riferimento alla classe del plug-in e tutti i tipi di contratto incorporato, il progetto dovrà fare riferimento agli assembly forniti dal SDK.Figura 4 descrive brevemente questi quattro assembly.

Figura 4 di assembly di riferimento per un progetto di applicazione mappa

Nome assembly Descrizione
Microsoft.Maps.Plugins.dll Contiene la classe base del plug-in e le classi di attributi correlate di procedura.
Microsoft.Maps.Core.dll Contiene tutti i tipi di contratto fornisce Bing Maps.
Microsoft.Maps.MapControl.Types.dll Contiene i tipi necessari per il controllo della mappa.
Microsoft.Maps.Extended.dll Contiene i tipi per interagire con la modalità di mapping StreetSide.

Accedere al un' bus API non al computer

Per ottenere informazioni di arrivo bus in tempo reale, potrà essere che utilizza pubblicamente disponibile un bus lo stoccaggio REST API (semplicemente definita oba API per il resto di questo articolo).Troverete informazioni dettagliate sulle API oba in code.google.com/p/onebusaway/wiki/OneBusAwayRestApi.(Si noti che l'API è attualmente disponibile per uso noncommercial ma ti viene richiesto di registrare per una chiave di applicazione prima di potervi accedere.Nel codice scaricabile di questo articolo, ho rimosso la chiave assegnata a me, se si desidera compilare e provare l'applicazione, è necessario sostituirlo con la propria chiave.)

Quando un'applicazione Silverlight tenta di accedere a un servizio Web in un dominio diverso, il runtime Silverlight impone che il servizio deve scegliere esplicitamente per consentire l'accesso tra domini.Un servizio indica il consenso collocando il file clientaccesspolicy.xml o crossdomain.xml nella radice del dominio in cui è ospitato il servizio.Ulteriori dettagli relativi a schemi di questi due file sono documentati in msdn.microsoft.com/library/cc197955%28VS.95%29 .Fortunatamente, l'API oba fornisce il file crossdomain.xml, che consente la mia applicazione mappa chiamata nel codice Silverlight.

Nella soluzione scaricabile, vedrete due progetti di libreria ObaApp e ObaLib.ObaApp è il progetto principale che contiene il plug-in di applicazione mappa, e fa riferimento a ObaLib.ObaLib è un altro progetto libreria di classi che incapsula tutte le classi di supporto per comunicare con l'API oba.Dopo aver apportato è una libreria separata in modo da poterlo facilmente riutilizzare in diversi progetti se necessario.Non verrà esaminato i dettagli di ogni classe in questa raccolta, ma si consiglia di esaminare il codice sorgente per ulteriori informazioni sulle classi in tale posizione.

La classe più importante sapere è la classe ObaSearchHelper che fornisce utili metodi ed eventi per eseguire la query per l'API oba:

 

public sealed class ObaSearchHelper
{
  public void SearchArrivalTimesForStop(string stopId);
  public event EventHandler<BusTripsEventArgs>
    SearchArrivalTimesForStopCompleted;
  public void SearchStopsByLocation(double latitude, double longitude, 
    double radius, int maxResultCount);
  public event EventHandler<BusStopsEventArgs> 
    SearchStopsByLocationCompleted;
  // more method/event pairs
  // ...
}

È facile individuare il modello utilizzato in questa classe. Per ogni endpoint REST dell'API oba, vi è un metodo per attivare la ricerca e un evento per segnalare il completamento della ricerca. Sottoscrittori di eventi è possono ottenere risultati da oggetti di argomento dell'evento.

Con questa classe utile pronta let’s dissect le classi principali del progetto ObaApp.

Definire l'entità della mappa

La prima operazione da eseguire quando si scrive un'applicazione mappa consiste nel definire l'entità della mappa. Ecco la definizione dell'entità dalla documentazione SDK: “ Un'entità è un elemento associato geo sulla mappa. Può essere un'entità mappa un punto, una polilinea, un poligono o una sovrimpressione immagine. ” The simple rule of thumb is that if you want to place something on the map, you need an instance of Entity to represent it. In genere, si desidera creare una sottoclasse di entità per aggiungere logica personalizzata per le entità e le proprietà aggiuntive. Nella mia applicazione, poiché si desidera mostrare le posizioni delle interruzioni di bus, ho scritto una classe BusStopEntity per rappresentare un'interruzione del bus. Figura 5 viene illustrata la classe BusStopEntity.

Figura 5 La classe BusStopEntity

public class BusStopEntity : Entity
{
  private readonly DependencyProperty NamePropertyKey =
    Entity.RetrieveProperty(“Name”, typeof(string));
  private BusStop _busStop;
  // Short name of this bus stop
  public string Name
  {
    get { return _busStop.Name; }
  }
  // Unique id of this bus stop
  public string StopId
  {
    get { return _busStop.Id; }
  }
  public BusStopEntity(BusStop busStop, 
    PushpinFactoryContract pushpinFactory)
  {
    _busStop = busStop;
    // Set the location of this Entity
    Location location = 
      new Location(_busStop.Latitude, _busStop.Longitude);
    this.Primitive = pushpinFactory.CreateStandardPushpin(location, “B”);
    // Set the name of this Entity
    this.SetValue(NamePropertyKey, _busStop.Name);
  }
}

La classe BusStopEntity espone due proprietà, Name e StopId, che verrà successivamente utilizzato per associare dati ai controlli dell'interfaccia utente. Questi valori provengono dall'istanza BusStop sottostante. Classe BusStop definito nel progetto ObaLib, incapsula i dati di un'interruzione di bus, ottiene dall'API oba.

Nel costruttore, è possibile inoltre impostare la primitiva e le proprietà Name. La proprietà primitive rappresenta il tipo (ad esempio punto, poligono o polilinea) e la posizione del mio entità. È possibile impostare il percorso per i valori dell'istanza BusStop longitudine e latitudine. Inoltre, l'impostazione della proprietà primitive al valore restituito di PushpinFactoryContract.CreateStandardPushpin fornisce le entità l'aspetto standard simboli di mappe Bing. Il tipo PushpinFactoryContract fornisce metodi utili per la creazione di simboli comuni elementi dell'interfaccia utente. Non è necessario utilizzarla se si desidera creare forme di puntina da disegno personalizzato. Qui è possibile solo in poche parole una lettera B (per bus) all'interno del simbolo, ma è possibile utilizzare un'immagine o un UIElement.

Anche se è possibile definire la proprietà Name nella mia sottoclasse, non essere riconosciuto da altri tipi di SDK, tali tipi semplicemente non conoscono le proprietà. Pertanto, è possibile impostare anche lo stesso valore alla proprietà di dipendenza Name, è possibile recuperare tramite la chiamata Entity.RetrieveProperty (“ nome ”, typeof(string)). In questo modo, è possibile attivare altre funzionalità recuperare il nome di un'entità di fine bus.

Scrivere il Plug-in Main

Come spiegato in precedenza, è necessario che una classe derivata da plug-in per rappresentare l'applicazione mappa. Figura 6 Visualizza mio, appropriatamente denominata ObaPlugin. Il plug-in Importa un totale di sei contratti. Si noti che tutti i contratti forniti dal mapping Bing seguano la convenzione di denominazione di Microsoft / *. La documentazione SDK fornisce descrizioni dettagliate di tutti i contratti possono essere importati, illustrato in di Figura 7.

Figura 6 Imports dichiarate nella classe ObaPlugin

public class ObaPlugin : Plugin
{
  #region Imports
  [ImportSingle(“Microsoft/LayerManagerContract”, ImportLoadPolicy.Synchronous)]
  public LayerManagerContract LayerManager { get; set; }
  [ImportSingle(“Microsoft/PopupContract”, ImportLoadPolicy.Synchronous)]
  public PopupContract PopupContract { get; set; }
  [ImportSingle(“Microsoft/ConfigurationContract”, 
    ImportLoadPolicy.Synchronous)]
  public ConfigurationContract ConfigurationContract { get; set; }
  [ImportSingle(“Microsoft/MapContract”, ImportLoadPolicy.Synchronous)]
  public MapContract Map { get; set; }
  [ImportSingle(“Microsoft/PushpinFactoryContract”, 
    ImportLoadPolicy.Synchronous)]
  public PushpinFactoryContract PushpinFactory { get; set; }
  [ImportSingle(“Microsoft/ContributorHelperContract”, 
    ImportLoadPolicy.Synchronous)]
  public ContributorHelperContract ContributorHelper { get; set; }
  #endregion

Figura 7 contratti importati tramite il ObaPlugin

Contract Type Descrizione
LayerManagerContract Consente a un plug-in aggiungere o rimuovere livelli di mappa.
PopupContract Allows a plug-in to show the pop-up UI when user hovers or clicks on the entities/pusphins.
ConfigurationContract Consente a un plug-in per il caricamento dinamico dei valori di configurazione dal file di configurazione in fase di esecuzione.
MapContract Consente a un plug-in per il controllo della mappa.
PushpinFactoryContract Consente a un plug-in per il rendering di simboli standard per l'entità.
ContributorHelperContract Consente a un plug-in creare asincrona o collaboratori di carico richiesta. (Si utilizzerà questo supporto per aggiungere successivamente “ driving direzioni ” e “ StreetSide ” collaboratore collegamenti personali popup.)

Dopo aver dichiarato le importazioni, l'override del metodo di inizializzazione virtuale:

public override void Initialize()
{
  // Obtain the application key from configuration file
  IDictionary<string, object> configs = 
    ConfigurationContract.GetDictionary(this.Token);
  string appKey = (string)configs[“ApplicationKey”];
  _searchHelper = new ObaSearchHelper(appKey);
  _searchHelper.SearchStopsByLocationCompleted += 
    OnSearchBusStopsCompleted;
  _searchHelper.SearchArrivalTimesForStopCompleted += 
    OnSearchArrivalTimesComplete;
  // Update the bus stop every time map view changes
  Map.TargetViewChangedThrottled += (s, e) => RefreshBusStops();
}

Questo metodo viene chiamato una sola volta dopo viene creata l'istanza del plug-in e sono soddisfatte tutte le importazioni dichiarate. Questa è la posizione ideale per eseguire le operazioni di inizializzazione che dipende da contratti importati. Se il plug-in ha le esportazioni, è necessario assicurarsi che tutte le proprietà esportate sono completamente istanziate dal tempo che inizializzazione restituisce.

Innanzitutto ottenere la chiave dell'applicazione dal file di configurazione tramite l'istanza ConfigurationContract importato e passare al costruttore ObaSearchHelper. Inserendo la chiave dell'applicazione nel file di configurazione, facilmente possibile modificarlo in qualsiasi momento senza dover ricompilare il progetto.

La seconda cosa che faccio è associare l'evento TargetViewChangedThrottled dall'istanza MapContract. Questo evento viene generato ogni volta che la visualizzazione della mappa sta per essere modificata, a livello di codice o tramite interazione dell'utente. Come suggerisce il nome, l'evento viene limitata internamente in modo da non generare troppe volte entro breve tempo. Pertanto, è un evento perfetto per valutare se si desidera sincronizzare le entità con la visualizzazione della mappa. In questo caso, è possibile chiamare il metodo RefreshBusStops per aggiornare l'elenco dei punti di bus. Ecco la definizione di RefreshBusStops:

internal void RefreshBusStops()
{
  if (Map.ZoomLevel >= 14)
  {
    // Search within the radius of 1km, maximum 150 results
    _searchHelper.SearchStopsByLocation(
      Map.Center.Latitude, Map.Center.Longitude, radius: 1000, 150);
  }
  else
  {
    // Clear all bus stops
    ClearBusStops();
  }
}

In questo caso, verificare che il livello di zoom corrente mappa è di almeno 14, quindi viene eseguita una chiamata al metodo SearchStopsByLocation, che restituirà un elenco di tutti i punti di bus entro un raggio intorno al centro della mappa specificato. In caso contrario, se lo zoom è inferiore a 14, ovvero che il mapping non è ingrandito in chiusura sufficientemente al livello città, è possibile cancellare tutti i punti di bus.

Al completamento del metodo SearchStopsByLocation (asincrono), viene generato l'evento SearchStopsByLocationCompleted, illustrato in Figura 8 , cui sottoscrivere precedentemente nel metodo Initialize.

Figura 8 gestore per l'evento SearchBusStopsCompleted

private int _searchCount;
private Dictionary<BusStop, int> _busStopCache = 
  new Dictionary<BusStop, int>();
private ObaLayer _layer;
private void OnSearchBusStopsCompleted(object sender, BusStopsEventArgs e)
{
  _searchCount++;
  // Contains new bus stops not present in the current view 
  Collection<BusStopEntity> addedEntities = 
    new Collection<BusStopEntity>();
  foreach (BusStop stop in e.BusStops)
  {
    // If this bus stop is not in the cache, it is a new one
    if (!_busStopCache.ContainsKey(stop))
    {
      addedEntities.Add(new BusStopEntity(stop, PushpinFactory));
    }
    // Marks this bus stop as being in the current search
    _busStopCache[stop] = _searchCount;
  }
  // Contains the old bus stops 
  // that should be removed from the current view
  Collection<BusStopEntity> removedEntities = 
    new Collection<BusStopEntity>();
  foreach (BusStopEntity bse in _layer.Entities)
  {
    // This bus stop belongs to the previous search, 
    // add it to removed list
    if (_busStopCache[bse.BusStop] < _searchCount)
    {
      removedEntities.Add(bse);
      _busStopCache.Remove(bse.BusStop);
    }
  }
// Tells the layer to add new in-view entities 
// and remove out-of-view ones 
      _layer.RefreshEntities(addedEntities, removedEntities);
}

Nota l'oggetto di tipo ObaLayer, verrà spiegato nella sezione successiva. Per ora, basti dire che questo oggetto è responsabile della gestione del contenuto e l'entità della mappa il pannello sinistro.

Si noti che è possibile utilizzare un Dictionary < BusStop, int >oggetto Aiutami a tenere traccia di elenco corrente dei punti bus visualizzati. Con l'aiuto di questo dizionario, ogni volta che viene visualizzato un insieme di interruzioni di bus nuovissima dalla chiamata al servizio è possibile determinare rapidamente l'interrompe nuovo che non sono già visualizzato, come l'interruzione precedente sono ora visualizzate per la modifica della visualizzazione mappa.

Si potrebbe chiedersi perché I non appena deselezionare fuori tutti i punti di bus correnti e Mostra il nuovo set di bus arresta completamente. Bene, infatti le prestazioni. Ho eseguito l'operazione, imporrebbe tutti i controlli di puntina da disegno per essere ricreati anche se molti di essi sono nella stessa posizione nelle visualizzazioni mappa vecchi e nuovi. Peggio ancora, gli utenti vedrà un breve flash quando i simboli sono stati rimossi e rapidamente aggiunti nuovamente. L'approccio Elimina entrambi questi svantaggi.

Mostra contenuto e simboli con un layer

The Plugin class represents your map app, but if you want to show UI representations of it, you need to create layers. Un livello è un concetto astratto che consente di inserire le entità sulla mappa come simboli (polilinee o poligoni) e visualizzare l'interfaccia utente personalizzata contenuto nel pannello sinistro. Facoltativamente, inoltre possibile inserire una sovrimpressione UI arbitraria su carta, ma non è necessario che per la mia applicazione. La maggior parte delle applicazioni dispongono di un solo livello.

Se hai utilizzato Photoshop, troverete il concetto molto simile a livelli di Photoshop. Pulsante Cronologia (situato nell'angolo inferiore sinistro della pagina) viene visualizzato l'elenco di tutti i livelli attualmente caricati. È possibile scegliere di mostrare o nascondere i layer oppure è possibile impostare un livello diventi attivo. Quando viene attivato un livello, relativo elemento di interfaccia utente del pannello viene visualizzato a sinistra pannello e tutte le entità sono portate avanti nello stack di indice z.

Nel codice un livello è una sottoclasse della classe astratta layer. Come illustrato in di Figura 9, ObaPlugin crea e gestisce un'istanza della classe ObaLayer, che deriva da layer.

Figura 9 di Classe ObaLayer

internal class ObaLayer : Layer
{
  private ObaPlugin _parent;
  private BusStopsPanel _resultPanel;
  private ObservableCollection<BusStopEntity> _busStopEntities;
  public ObaLayer(ObaPlug-in parent) : base(parent.Token)
  {
    _parent = parent;
    // Contains the set of active bus stop entities 
    // for data binding purpose
    _busStopEntities = new ObservableCollection<BusStopEntity>();
    _resultPanel = new BusStopsPanel(parent, this);
    _resultPanel.DataContext = _busStopEntities;
    this.Title = “Bus stops”;
    this.Panel = _resultPanel;
  }
  ...
}

Nel costruttore di ObaLayer, è possibile impostare il titolo del mio livello, che verrà visualizzato nella parte superiore del riquadro sinistro. Inoltre possibile impostare la proprietà pannello a un'istanza del controllo utente BusStopsPanel, occupa l'area intero pannello sinistro se il livello diventa attiva. Proprietà DataContext del controllo utente è impostata su un'istanza di ObservableCollection <Entity>.

Così come visualizzato il livello? Che avviene ObaPlugin come illustrato in di Figura 10.

Figura 10 ShowResultLayer metodo visualizza l'istanza ObaLayer all'utente

public override void Activate(IDictionary<string, string> activationParameters)
{
  ShowResultLayer();
  RefreshBusStops();
}
private void ShowResultLayer()
{
  if (_layer == null)
  {
    _layer = new ObaLayer(this);
  }
  if (LayerManager.ContainsLayer(_layer))
  {
    LayerManager.BringToFront(_layer);
  }
  else
  {
    LayerManager.AddLayer(_layer);
  }
}

Override metodo Activate viene chiamato ogni volta che la mia applicazione mappa viene attivato tramite la raccolta di mapping applicazioni. Per visualizzare il layer, riferimenti al tipo LayerManagerContract importati in precedenza. La classe LayerManagerContract definisce i metodi per lavorare con i livelli. Se il livello è già stato aggiunto, è possibile impostarlo su attivo chiamando il metodo BringToFront. Tentativo di aggiungere che lo stesso livello due volte genera un'eccezione.

Di Figura 8, chiamato il metodo ObaLayer.RefreshEntities aggiornamento interrompe il bus. Figura 11 viene illustrata la definizione.

Figura 11 la definizione di metodo ObaLayer.RefreshEntities

public void RefreshEntities(
  ICollection<BusStopEntity> addedEntities,
  ICollection<BusStopEntity> removedEntities)
{
  foreach (BusStopEntity entity in removedEntities)
  {
    // Remove this pushpin from the map
    this.Entities.Remove(entity);
    // Remove this bus stop entry from the panel
    _busStopEntities.Remove(entity);
  }
  foreach (BusStopEntity entity in addedEntities)
  {
    // Add this pushpin to the map
    this.Entities.Add(entity);
    // Add this bus stop entry to the panel
    _busStopEntities.Add(entity);
    // Register this entity to have popup behavior
    _parent.PopupContract.Register(entity, OnPopupStateChangeHandler);
  }
}

Per aggiungere o rimuovere un'entità sulla mappa, utilizzare la proprietà di insieme Layer.Entities. E per ogni nuovo BusStopEntity chiamo il metodo PopupContract.Register per registrare per l'interfaccia utente a comparsa sul mio pusphin bus stop. Il metodo Register accetta l'entità e un metodo di callback viene richiamato ogni volta che il controllo popup Cambia stato sull'entità (vedere di Figura 12).

Figura 12 Modifica dello stato di un controllo popup

private void OnPopupStateChangeHandler(PopupStateChangeContext context)
{
  if (context.State == PopupState.Closed)
  {
    return;
  }
  BusStopEntity entity = (BusStopEntity)context.Entity;
  context.Title = entity.Name;
  context.Content = “Bus numbers: “ + entity.BusRoutesAsString;
  // Only shows contributors link in the normal state of popup
  if (context.State == Pop-upState.Normal)
  {
    // Add Arrival times contributor
    context.Contributors.Add(new BusStopContributor(_parent, entity));
    Dictionary<string, object> parameter = new Dictionary<string, object>
    {
      {“Entity”, entity}
    };
    var contributorHelper = _parent.ContributorHelper;
    // Add Directions contributor
    context.Contributors.Add(contributorHelper.
      CreateDemandLoadContributor(
      “Microsoft/DirectionsContributorFactoryContract”, 
      parameter, “Directions”));
    // Add Streetside contributor
    context.Contributors.Add(contributorHelper.CreateAsyncContributor(
      “Microsoft/StreetsideContributorFactoryContract”, parameter));
  }
}

All'interno del callback popup argomento del metodo di tipo PopupStateChangeContext accedere automaticamente allo stato corrente di popup e l'entità attualmente in finestra popup. In base a quelli, è possibile impostare il titolo con il nome del bus stop popup e il contenuto del popup con la proprietà BusStopEntity.BusRoutesAsString, che restituisce un elenco separato da virgole di route bus che gestiscono questo particolare fermata bus.

Se il popup è nello stato normale, è possibile inoltre aggiungere collegamenti collaboratore tre a popup tramite la proprietà di insieme collaboratori, collaboratore “ arrivo volte ” indica l'ora di arrivo interrompere questo bus collaboratore Directions richiama la funzione direzioni determinanti e collaboratori Streetside passa alla modalità a livello di strada mappa.

Un collaboratore è rappresentato da un collegamento ipertestuale nella parte inferiore del controllo popup. Consente di applicazioni di mapping richiamare alcune funzionalità principali di mappe Bing. Per generare i collaboratori, chiamare uno dei due metodi di tipo ContributorHelperContract: CreateAsyncContributor o CreateDemandLoadContributor. Entrambi i metodi restituiscono un collaboratore di proxy in modo sincrono e rinviare il caricamento dell'istanza reale collaboratore. L'unica differenza è che la CreateAsyncContributor carica il Collaboratore reale appena restituito, mentre CreateDemandLoadContributor solo avviene quando il collegamento di collaboratori proxy viene richiamato la prima volta.

BusStopsPanel UserControl

BusStopsPanel è un controllo utente, che viene utilizzato per visualizzare l'elenco dei punti di bus nella visualizzazione nel riquadro sinistro (come illustrato in di Figura 1). Contiene un'istanza di ItemsControl con la proprietà ItemTemplate imposta un DataTemplate personalizzato (vedere di Figura 13). Si noti che si attiva modalità di virtualizzazione UI per mio ItemsControl impostando la proprietà ItemsPanel per utilizzare un VirtualizingStackPanel. In generale, è consigliabile applicare UI virtualizzazione a ItemsControl se l'applicazione può caricare centinaia di elementi in essa.

Figura 13 Di BusStopsPanel UserControl

<UserControl.Resources>
  <DataTemplate x:Key=”BusStopTemplate”>
    <Border Margin=”2,0,2,12”
      <StackPanel>
        <TextBlock Text=”{Binding Name}” FontSize=”14” FontWeight=”Bold”  
          TextWrapping=”Wrap” />
        <TextBlock Text=”{Binding BusRoutesAsString, StringFormat=’Bus numbers:
          {0}’}” FontSize=”12” TextWrapping=”Wrap” />
          <HyperlinkButton Content=”Arrival times” Click=”OnBusStopClick” 
            Style=”{StaticResource App.P2.Hyperlink}”         
              HorizontalAlignment=”Left” />
      </StackPanel>
    </Border>
  </DataTemplate>
  <ControlTemplate x:Key=”ScrollableItemsControl”    
    TargetType=”ItemsControl”>
    <ScrollViewer Style=”{StaticResource App.ScrollViewer}”  
      VerticalScrollBarVisibility=”Auto”>
      <ItemsPresenter />
    </ScrollViewer>
  </ControlTemplate>
</UserControl.Resources>
    
<ItemsControl 
  ItemsSource=”{Binding}”
  VirtualizingStackPanel.VirtualizationMode=”Recycling”
  ItemTemplate=”{StaticResource BusStopTemplate}” 
  Template=”{StaticResource ScrollableItemsControl}”>
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <VirtualizingStackPanel />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
</ItemsControl>

All'interno del bus stop DataTemplate è stato aggiunto un controllo HyperlinkButton che, quando selezionato, trigger della ricerca per l'ora di arrivo del bus corrispondente interromperà:

private void OnBusStopClick(object sender, RoutedEventArgs e)
{
  FrameworkElement element = (FrameworkElement)sender;
  BusStopEntity entity = (BusStopEntity)element.DataContext;
  _plugin.SearchArrivalTimes(entity);
}

Si noti che la proprietà Style è impostata su un oggetto dall'insieme StaticResource con la chiave come “ App.P2.Hyperlink. ” Bing Maps offre un insieme predefinito di risorse di interfaccia utente, ad esempio stili e ControlTemplates di controlli comuni, nonché standard colori e pennelli utilizzati dal mapping Bing stesso. Mappa app autori sono invitati ad applicare queste risorse per gli elementi dell'interfaccia utente in modo che abbiano lo stesso aspetto nativi elementi dell'interfaccia utente. Consultare la documentazione di tutte le risorse fornite da Bing Maps.

SearchArrivalTimes è un metodo interno della classe ObaPlugin. Chiama il metodo ObaSearchHelper.SearchArrivalTimesForStop per recuperare gli orari di arrivo per l'interruzione bus specificato:

internal void SearchArrivalTimes(BusStopEntity _entity)
{
  _searchHelper.SearchArrivalTimesForStop(_entity.StopId, _entity);
}

Al termine della ricerca, il plug-in indicherà ObaLayer per visualizzare l'ora di arrivo nel pannello sinistro. ObaLayer avviene modificando dinamicamente le proprietà Title e Panel.

Test e debug mapping applicazioni

Al termine di codifica, è opportuno testare l'applicazione. Il sito mappe Bing è una modalità di sviluppo viene attivata aggiungendo un “ sviluppatore = 1 ” parametro di query all'URL seguente: https://www.Bing.com/Maps/Explore/?Developer=1. In modalità sviluppatore, è possibile verificare l'applicazione mappa “ mappa app test strumento ” che possono essere attivati tramite la raccolta di applicazioni mappa stessa. Lo strumento di test mappa applicazione consente di selezionare gli assembly plug-in dal disco rigido locale. Quindi carica il plug-in nel sito come avviene con tutti i plug-in nativi. Per eseguire il debug del codice, allegare VS.NET browser durante il caricamento dell'applicazione. Assicurarsi di che impostare il tipo di codice di debug di Silverlight.

Invio del mapping applicazioni

Infine, quando si è soddisfatti del codice, è possibile inviare l'applicazione venga pubblicata ufficialmente al sito mappe Bing. È possibile inviare una nuova applicazione e visualizzare lo stato di invio precedente nell'area Bing mapping account (bingmapsportal.com ). La documentazione SDK è dettagliato istruzioni sull'invio di applicazione e vengono elencati i requisiti che delle applicazioni devono soddisfare per essere approvato.

Chiamare per azione

Quindi, questo è quanto: applicazione trasferimento vero e proprio, in tempo reale che non richiesta una grande quantità di codice. il SDK fornisce i blocchi predefiniti che semplificano la creazione di applicazioni basate su carta un'esperienza gratificante e piacevole. Consiglia di scaricare il SDK oggi, informazioni su esso e iniziare a scrivere applicazioni di mapping.

Luan Nguyen ha lavorato come uno sviluppatore del team mappe Bing, precedentemente noto come Microsoft Virtual Earth, quasi quattro anni. Era membro del team della funzionalità di shell, che era responsabile della shell del sito Bing mappe e Bing mappa App SDK framework. Ha recentemente ha scambiato il team di ASP.NET.

Grazie ai seguenti esperti tecnici per la revisione di questo articolo: Alan Paulin, Chris Pendleton , Dan Polivy e Greg Schechter