Este artículo proviene de un motor de traducción automática.

Aplicaciones para Bing Map

Construcción de una aplicación de tránsito en tiempo real utilizando el SDK para aplicaciones de Bing Map

Luan Nguyen

Descargar el ejemplo de código

Durante la conferencia Tech•Ed 2010 en junio, Microsoft ha anunciado la disponibilidad de libre Bing mapa App SDK, que permite a los programadores escribir aplicaciones centradas en el mapas en la parte superior de los mapas de Bing explorar el sitio en bing.com/maps/explore de /.

Esto supone una gran oportunidades para las organizaciones, empresas o aficionados a crear sus propias experiencias de asignación de mapas de Bing.Las empresas pueden escribir aplicaciones para anunciar sus productos o para complementar los servicios en línea.Por ejemplo, de bestparking.com desarrolló una aplicación “ Buscador de estacionamiento ”, que le ayudará a encontrar todas las instalaciones de estacionamiento en la ciudad con su base de datos.

Para ver el aspecto de una aplicación de mapas, vaya a los mapas de Bing explorar el sitio y haga clic en el botón MAP APPS cerca de la esquina inferior izquierda de la página.Se abrirá la Galería de mapa de las aplicaciones, que muestra las aplicaciones disponibles.Ya hay muchas aplicaciones destacadas la galería, y continúa creciendo.

En este artículo, describiré lo que se tarda en escribir una aplicación de mapa mediante el SDK de aplicación de mapa de Bing.Guiaremos a través del desarrollo de una aplicación de ejemplo que muestra la información de la llegada de bus en tiempo real en el Condado de King, estado de Washington.Esta aplicación se inspiró en la aplicación de un Bus Away popular.

El producto final

Antes de se trata en el código, let’s veamos lo que la aplicación mapa final tendrá el siguiente aspecto.Cuando se activa, si el mapa se amplía hasta el área del Condado de King, mi aplicación de mapa mostrará en el panel izquierdo, la lista de todas las paradas de autobús dentro del área de visualización de mapa (consulte de figura 1).

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

Figura 1 de la información de bus de muestra de la aplicación de OBA en el panel izquierdo y marcadores en el mapa

Detención de cada bus tiene información acerca de todos los buses de esa detención de servicio.Si hace clic en el hipervínculo “ el tiempo de llegada ” de cada parada obtendrá el segundo panel, que muestra horas en las próximas llegada (consulte de figura 2).

image: Bus Arrival Times for a Particular Bus Stop

La figura 2 de horas de llegada de bus para un determinado Stop de Bus

La aplicación también coloca un marcador de aspecto atractivo (marcado con la letra B) en cada parada de bus en el mapa.Se puede interactuar con los marcadores para activar una ventana emergente, desde el que se pueden invocar comandos comunes para una detención de bus específico, como, por ejemplo, al obtener de conducción o recorrer instrucciones a o (vea de figura 3) de ella.

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

La figura 3 de hacer clic en un marcador muestra una interfaz de usuario pop-up con información adicional

Descargar el SDK de aplicación de mapa de Bing

Antes de comenzar a escribir su primera aplicación de mapas, tiene que instalar el SDK de aplicación de mapa de Bing en connect.microsoft.com/bingmapapps de .El SDK proporciona a los ensamblados de referencia, un proyecto de ejemplo y documentación sin conexión.Además, debido a que se basa en el SDK de Silverlight 4, deberá instalar el 4 de Silverlight Tools para Visual Studio 2010, disponible en silverlight.net/getstarted/ de .

Fundamentos de la aplicación de mapa

Los mapas de Bing Explorar sitio se creó con la extensibilidad, como una de las principales prioridades.El equipo de mapas de Bing deseado para que los desarrolladores de todo el mundo agregar fácilmente funciones le resulte útiles y que sería útil para otros usuarios.En este sentido, una aplicación de mapa de es una característica concreta que utilizar los servicios de bloques de creación proporcionados por el centro de mapas de Bing.Si examina el sitio de mapas de Bing predeterminado, las instrucciones de conducción, características de búsqueda de búsqueda y la ubicación de negocio se todos generan desde las mismas unidades de creación.

Con ese objetivo en mente, el equipo de mapas de Bing decidido crear un marco extensible para admitir el concepto de asignación de aplicaciones.Cuando se escribe sobre el marco de trabajo, las aplicaciones de mapa de sacar partido de un enfoque de estilo de la inserción de dependencia para proporcionar acceso a la funcionalidad, similar a la se encuentra en el Framework de extensibilidad administradas (MEF).

En el núcleo del marco de trabajo es el concepto de complementos.Un complemento es una unidad de extensibilidad que permite a los desarrolladores agregar funciones de una manera fácil de mantener sin conexión.Se puede considerarse como el equivalente de una parte compuesta en la terminología de MEF.A través de atributos, un complemento declara las importaciones que necesita, así como las exportaciones que desea compartir.En tiempo de ejecución, el marco de trabajo se resuelve dependencias entre los complementos y coinciden con las importaciones con las exportaciones del mismo contrato.

Para escribir una aplicación de asignación, se crea una biblioteca de clases de Silverlight 4 contiene exactamente una subclase de la clase base del complemento.Para poder hacer algo útil, el complemento es probable que importará un número de contratos integrados que permiten tener acceso a diversos servicios de núcleo.La documentación del SDK tiene una sección que se enumeran todos los contratos integrados exportados por el marco de trabajo.

Para hacer referencia a la clase de complemento y todos los tipos integrados de contrato, su proyecto deberá hacer referencia a los ensamblados suministrados de SDK.La figura 4 se describen brevemente estos cuatro ensamblados.

La figura 4 de ensamblados de referencia para un proyecto de aplicación del mapa

Nombre de ensamblado Descripción
Microsoft.Maps.Plugins.dll Contiene la clase base del complemento y relacionados con las clases de atributos de importación o exportación.
Microsoft.Maps.Core.dll Contiene todos los tipos de contrato que proporciona mapas Bing.
Microsoft.Maps.MapControl.Types.dll Contiene los tipos necesarios para trabajar con el control de mapa.
Microsoft.Maps.Extended.dll Contiene los tipos de interacción con el modo de asignación de StreetSide.

El bus de una ubicación de la API de acceso

Para obtener información de la llegada de bus en tiempo real, te lo utilice de la disposición del público un Bus Away REST API (simplemente denominada API de OBA para el resto de este artículo).Encontrará detalles acerca de la API de OBA en code.google.com/p/onebusaway/wiki/OneBusAwayRestApi de .(Tenga en cuenta que la API está actualmente disponible para su uso no comercial, pero tiene que registrar para una clave de la aplicación antes de que tiene acceso a él.En el código descargable de este artículo, he quitado la clave asignada a mí, por lo que si desea compilar y probar la aplicación por sí mismo, deberá reemplazarlo con su propia clave.)

Cuando trata de una aplicación de Silverlight tener acceso a un servicio Web en un dominio diferente, el tiempo de ejecución de Silverlight obliga a que el servicio explícitamente debe suscribirse para permitir el acceso entre dominios.Un servicio indica su consentimiento, coloque el archivo crossdomain.xml o clientaccesspolicy.xml en la raíz del dominio donde se hospeda el servicio.Obtener información más detallada acerca de los esquemas de estos dos archivos está documentado en msdn.microsoft.com/library/cc197955%28VS.95%29 de .Por suerte, la API de OBA proporciona el archivo crossdomain.xml, que permite que mi aplicación mapa lo llame en el código de Silverlight.

En la solución que se pueden descargar, verá dos proyectos de biblioteca, ObaApp y ObaLib.ObaApp el proyecto principal, que contiene el complemento de aplicación de mapa, y hace referencia a ObaLib.ObaLib es otro proyecto de biblioteca de clase que encapsula todas las clases de aplicación auxiliar para comunicarse con la API de OBA.Se han efectuado, una biblioteca independiente, de forma fácil reutilizarla en diferentes proyectos si es necesario.No entraré en detalles de cada clase de esta biblioteca, pero es conveniente que examine el código fuente para obtener más información sobre las clases de allí.

La clase más importante saber es la clase ObaSearchHelper, que proporciona la métodos prácticos y eventos para realizar consultas a la API de 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
  // ...
}

Es fácil identificar el patrón utilizado en esta clase. Para cada extremo REST de la API de OBA, hay un método para desencadenar un evento correspondiente para señalar la finalización de dicha búsqueda y de la búsqueda. Los suscriptores de los eventos pueden obtener los resultados de los objetos de argumento de evento.

Con esta clase práctica está lista, let’s para analizar minuciosamente las clases principales del proyecto ObaApp.

Definir la entidad de mapa

Lo primero que debe hacer cuando se escribe una aplicación de asignación es definir la entidad de asignación. Ésta es la definición de la entidad de la documentación de SDK: “ Una entidad es un elemento asociado a geo en el mapa. Una entidad de asignación puede ser un punto, una polilínea, un polígono o una superposición de imagen. ” La simple regla empírica es que si desea poner algo en el mapa, necesita una instancia de la entidad para representarlo. Normalmente, desea crear una subclase de la entidad para agregar propiedades adicionales y la lógica personalizada para las entidades. En mi aplicación, ya que deseo mostrar las ubicaciones de paradas de autobús, escribí una clase BusStopEntity para representar una detención de bus. La figura 5 muestra la clase BusStopEntity.

La figura 5 de La clase 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);
  }
}

Mi clase BusStopEntity expone dos propiedades, Name y StopId, que posteriormente utilizará para enlazar a controles de interfaz de usuario. Estos valores proceden de la instancia de BusStop subyacente. Si se define en el proyecto ObaLib, la clase BusStop encapsula los datos de una parada de bus, que se obtiene de la API de OBA.

En el constructor, también establecí el primitiva y las propiedades de nombre. La propiedad simple representa el tipo (por ejemplo, punto, polígono o polilínea) y la ubicación de la entidad. Establece la ubicación a los valores de longitud y latitud de la instancia BusStop. Además, proporciona al establecer la propiedad simple en el valor devuelto de PushpinFactoryContract.CreateStandardPushpin a mi entidad el aspecto de los marcadores de mapas de Bing estándar. El tipo de PushpinFactoryContract proporciona métodos útiles para la creación de elementos de interfaz de usuario común de marcador. No debe utilizarlo si desea crear sus propias formas de marcador personalizado. Aquí simplemente poner una letra B (para el bus) dentro del marcador, pero se puede utilizar una imagen o de cualquier UIElement.

Aunque la propiedad Name se define en la subclase, no se reconoce por otros tipos en el SDK, los tipos simplemente no tengan ningún conocimiento de la propiedad. Por lo tanto, también establecí el mismo valor para la propiedad de dependencia de nombre, que puedo recuperar a través de la llamada Entity.RetrieveProperty (“ Name ”, typeof(string)). De esta manera, permiten otras funciones recuperar el nombre de una entidad de la detención del bus.

Escribir el complemento principal

Como se explicó anteriormente, necesitará una clase derivada de complemento para representar la aplicación del mapa. La figura 6 muestra mío, denominada acertadamente ObaPlugin. Mi complemento importa un total de seis contratos. Tenga en cuenta que todos los contratos proporcionados mapas Bing siguen la convención de nomenclatura de Microsoft / *. La documentación de SDK proporciona descripciones detalladas de todos los contratos que pueden ser importado, se muestra en de figura 7.

La figura 6 de Imports declarados en la clase 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

La figura 7 de contratos importan por la ObaPlugin

Tipo de contrato Descripción
LayerManagerContract Permite que un complemento agregar o quitar la asignación de capas.
PopupContract Permite que un complemento mostrar el 
UI emergente cuando el usuario se desplaza o hace clic en el 
entities/pusphins.
ConfigurationContract Permite que un complemento cargar dinámicamente los valores de configuración del archivo de configuración en tiempo de ejecución.
MapContract Permite que un complemento controlar la asignación.
PushpinFactoryContract Permite que un complemento representar marcadores estándar para sus entidades.
ContributorHelperContract Permite que un complemento para crear asincrónica o colaboradores de carga de demanda. (Usaré este auxiliar para agregar más tarde “ indicaciones de conducción ” y “ StreetSide ” colaborador vínculos a la ventana emergente).

Después de declarar las importaciones, invalido el método Initialize virtual:

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();
}

Este método se llama exactamente una vez después de que se construye la instancia del complemento y se cumplen todas las importaciones declaradas. Éste es el lugar perfecto para realizar cualquier trabajo de inicialización que depende de los contratos importados. Si el complemento tiene las exportaciones, también se necesita para mantenerla que completamente se crean instancias de todas las propiedades exportadas en el momento en que devuelve Initialize.

En primer lugar, obtener la clave de la aplicación desde el archivo de configuración a través de la instancia de ConfigurationContract importado y pasarla al constructor ObaSearchHelper. Colocando la clave de la aplicación en el archivo de configuración, puede cambiar fácilmente en cualquier momento sin volver a compilar el proyecto.

La segunda cosa que hago es enlazar el evento TargetViewChangedThrottled desde la instancia MapContract. Este evento se provoca cada vez que vista del mapa se va a cambiar, ya sea mediante programación o interacción del usuario. Como su nombre indica, el evento se reduce internamente, de modo que no se desencadena demasiadas veces dentro de una duración corta. Por lo tanto, es un evento perfecto para tener en cuenta si desea mantener las entidades en sincronización con la vista del mapa. En mi caso, llamo al método RefreshBusStops para actualizar la lista de paradas de autobús. Ésta es la definición de 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();
  }
}

En este caso, se puede comprobar que el nivel de zoom del mapa actual es al menos 14, a continuación, emito una llamada al método SearchStopsByLocation, que devolverá la lista de todas las paradas de autobús dentro de un radio especificado alrededor del centro del mapa. De lo contrario, si el nivel de zoom es menor que 14, lo que significa que la asignación no está ampliada en suficientemente cerca como para el nivel de ciudad, borrar todas las paradas de autobús.

Cuando el método SearchStopsByLocation completa (de forma asincrónica), provoca el evento SearchStopsByLocationCompleted, que se muestra en de figura 8 , que ha suscrito a anteriormente en el método Initialize.

La figura 8 del controlador para el 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);
}

Tenga en cuenta el objeto de tipo ObaLayer, que explicaré en la sección siguiente. Por ahora, basta con decir que este objeto es responsable de administrar las entidades en el mapa y el contenido del panel izquierdo.

Tenga en cuenta que use un diccionario < BusStop, int >objeto que me ayude a realizar un seguimiento de la lista actual de paradas de autobús mostradas. Con la Ayuda de este diccionario, cada vez que reciba un conjunto completamente nuevo de paradas de bus de la llamada de servicio, puedo rápidamente determinar las posiciones de nuevas que ya no se muestran, así como la detiene antigua que ahora no esté visibles debido a que el cambio de vista del mapa.

Quizá se pregunte por qué I no simplemente desactive fuera todas las paradas de autobús actuales y mostrar el nuevo conjunto de paradas de autobús por completo. Bueno, el motivo es el rendimiento. Si lo hizo, obligaría a todos los controles de marcador que volver a crear, aunque muchos de ellos en la misma ubicación en las vistas de mapa antiguos y nuevos de ambos. Peor aún, los usuarios podrán ver un breve parpadeo cuando los marcadores se han quitado y rápidamente se agrega de nuevo. Mi enfoque elimina ambos de estos puntos débiles.

Mostrar contenido y los marcadores con una capa

La clase del complemento representa la aplicación mapa, pero si desea mostrar las representaciones de la interfaz de usuario de la misma, tiene que crear capas de . Una capa es un concepto abstracto que permite colocar las entidades en el mapa como marcadores (polilíneas o polígonos) y para mostrar la interfaz de usuario personalizado contenido en el panel izquierdo. Si lo desea, también puede colocar una superposición de interfaz de usuario arbitraria en la parte superior de la asignación, pero no necesito para mi aplicación. La mayoría de las aplicaciones tienen una única capa.

Si ha utilizado Photoshop, encontrará el concepto muy similares a las capas de Photoshop. El botón Historial (que se encuentra en la esquina inferior izquierda de la página) muestra la lista de todas las capas cargadas en ese momento. Puede elegir mostrar u ocultar de ninguna capa, o puede establecer una capa para activarse. Si se activa de una capa, su elemento de interfaz de usuario del panel se muestra en la izquierda, panel y todas sus entidades pasan en la pila de z-index.

En el código, una capa es una subclase de la clase abstracta de la capa. Como se muestra en de figura 9, ObaPlugin crea y administra una instancia de la clase ObaLayer, que se deriva de la capa.

La figura 9 de La clase de 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;
  }
  ...
}

En el constructor de ObaLayer, establecer el título de la capa, que se mostrará en la parte superior del panel izquierdo. Establezco la propiedad de panel a una instancia del control de usuario BusStopsPanel, que ocupará la región de todo el panel izquierdo, si se convierte en la capa activa. Se establece la propiedad DataContext del control de usuario a una instancia de un ObservableCollection <Entity>.

¿Por lo tanto, cómo se muestra la capa? Que se realiza mediante ObaPlugin tal como se muestra en de figura 10.

La figura 10 de método ShowResultLayer muestra la instancia ObaLayer para el usuario

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);
  }
}

Cada vez que mi aplicación de asignación es activa a través de la Galería de mapa de las aplicaciones, se llama al método Activate de reemplazo. Para mostrar la capa, hacen referencia al tipo LayerManagerContract que se han importado anteriormente. La clase LayerManagerContract define métodos para trabajar con las capas. Si ya se ha agregado la capa, establece a activa llamando al método BringToFront. Se está intentando agregar que dos veces se produce una excepción de la misma capa.

En de figura 8, llama el método ObaLayer.RefreshEntities para actualizar las paradas de autobús. La figura 11 muestra su definición.

La figura 11 de la definición de método 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);
  }
}

Para agregar o quitar una entidad en el mapa, utilizo la propiedad de colección Layer.Entities. Y para cada nuevo BusStopEntity, llama al método PopupContract.Register para registrarse en la interfaz de usuario emergente en mi pusphin de detención del bus. El método Register acepta la entidad y un método de devolución de llamada que se invoca siempre que el control emergente cambia el estado de la entidad (consulte de figura 12).

La figura 12 de cambiar el estado de un control emergente

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));
  }
}

Dentro de la devolución de llamada emergente, el argumento de método del tipo PopupStateChangeContext me proporciona acceso al estado actual de la ventana emergente y a la entidad actualmente en la ventana emergente. Basándose en estas, establezco el título emergente con el nombre de la detención del bus y el contenido emergente con la propiedad BusStopEntity.BusRoutesAsString, que devuelve una lista separada por comas de las rutas de bus que actúa de esta parada de bus específico.

Si la ventana emergente que se encuentra en estado normal, también se agrega tres vínculos de colaborador en la ventana emergente a través de la propiedad de colección de los colaboradores, el colaborador “ el tiempo de llegada ” muestra la hora de llegada de esta parada de bus, el colaborador direcciones invoca la función de indicaciones de conducción y el colaborador Streetside se pasa al modo de asignación de nivel de calle.

Un colaborador está representado por un hipervínculo en la parte inferior del control emergente. Permite que las aplicaciones de mapa invocar una característica determinada principales de mapas de Bing. Para generar los colaboradores, se llama a uno de los dos métodos del tipo ContributorHelperContract: CreateAsyncContributor o CreateDemandLoadContributor. Ambos métodos devuelven un colaborador de proxy de forma sincrónica y aplazan la carga de la instancia real del colaborador. La única diferencia es que la CreateAsyncContributor carga el colaborador real tan pronto como lo devuelve, mientras que CreateDemandLoadContributor sólo lo hace cuando el vínculo del colaborador de proxy se llama a la primera vez.

BusStopsPanel UserControl

BusStopsPanel es un control de usuario, que es responsable de mostrar la lista de vista de bus se detiene en el panel izquierdo (como en de figura 1). Contiene una instancia de ItemsControl con la propiedad ItemTemplate establecida en una plantilla de datos personalizado (vea de figura 13). Tenga en cuenta que se activa en modo de virtualización de la interfaz de usuario para el ItemsControl estableciendo la propiedad ItemsPanel para utilizar un VirtualizingStackPanel. Por lo general, es una buena práctica de virtualización de la interfaz de usuario se aplican a ItemsControl si su aplicación puede cargar cientos de elementos en él.

La figura 13 del 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>

Se ha agregado un control HyperlinkButton, dentro de la plantilla de datos de la detención de bus que, al hacer clic, el desencadenador de la búsqueda de las horas de llegada del bus correspondiente dejará de:

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

Tenga en cuenta que su propiedad Style se establece en un objeto de la colección StaticResource, con la llave como "App.P2.Hyperlink". Bing mapas proporciona un conjunto predeterminado de los recursos de la interfaz de usuario, tales como estilos y ControlTemplates de controles comunes, así como estándar colores y pinceles utilizadas mapas de Bing por sí mismo. Los autores de aplicaciones de mapa se recomienda aplicar estos recursos a sus elementos de interfaz de usuario, por lo que tienen el mismo aspecto como elementos de interfaz de usuario nativos. Consulte la documentación para todos los recursos proporcionados por mapas Bing.

SearchArrivalTimes es un método interno de la clase ObaPlugin. Llama al método ObaSearchHelper.SearchArrivalTimesForStop recuperar horas de llegada de la detención de bus especificada:

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

Una vez finalizada la búsqueda, el complemento se le indicará ObaLayer para mostrar las horas de llegada en el panel izquierdo. ObaLayer para ello, cambiando sus propiedades de título y el panel de forma dinámica.

Probar y depurar el aplicación de mapa

Cuando haya terminado de codificación, desea probar la aplicación. El sitio de mapas de Bing dispone de un modo para programadores que se habilita agregando un “ desarrollador = 1 ” parámetro de consulta a la dirección URL, como la siguiente: https://www.Bing.com/Maps/explore/?Developer=1. En el modo de programador, probar la aplicación de mapa con la “ mapa app herramienta de prueba, ” que se puede activar a través de la Galería de aplicaciones de mapa del misma. La herramienta de prueba de la aplicación de asignación permite seleccionar los ensamblados de complementos de la unidad de disco duro local. A continuación, carga el complemento en el sitio igual que ocurre con todos los complementos nativos. Para depurar el código, se debe adjuntar VS.NET para el explorador mientras se carga la aplicación. Asegúrese de que se establece el tipo de código de depuración en Silverlight.

Mapa de la aplicación de envío

Por último, cuando esté satisfecho con el código, puede enviar su aplicación para que se publicó oficialmente en el sitio de mapas de Bing. Puede enviar una nueva aplicación y ver el estado de presentaciones con anterioridad en el centro de cuenta de mapas de Bing (bingmapsportal.com ). La documentación del SDK ha detallado de instrucciones sobre el envío de la aplicación y muestra los requisitos de que las aplicaciones deben cumplir para ser aprobada.

Llame a la acción

Por lo tanto, ahí lo tiene: una aplicación de tránsito de altas prestaciones y en tiempo real que no requiere una gran cantidad de código. El SDK incluye las unidades de creación que facilitar la escritura de aplicaciones centradas en la asignación de una experiencia agradable y gratificante. Le animo a descargar el SDK de hoy en día, aprenderlo y empezar a escribir sus propias aplicaciones de mapa.

Luan Nguyen ha trabajado como desarrollador en el equipo de mapas de Bing (anteriormente conocido como Microsoft Virtual Earth) casi cuatro años. Fue un miembro del equipo de la función Shell, que era responsable del shell de marco de trabajo del sitio Bing mapas y el SDK de aplicación de mapa de Bing. Ha cambiado recientemente en el equipo de ASP.NET.

Gracias a los siguientes expertos técnicos de este artículo: Alan PaulinChris Pendletonde , Dan Polivy de y de Greg Schechter