Este artigo foi traduzido por máquina.

Bing mapa de aplicativos

Criando um aplicativo de tráfego em tempo real usando o SDK do Bing mapa de aplicativo

Luan Nguyen

Baixe o código de exemplo

Durante a conferência Tech • Ed 2010 em junho, a Microsoft anunciou a disponibilidade do livre Bing mapa App SDK, que permite que os desenvolvedores escrevam aplicativos centrados no mapa de mapas de Bing explorar o site localizado em bing.com/maps/explore de /.

Isso apresenta muitas oportunidades para as organizações, as empresas ou entusiastas para criar suas próprias experiências de mapeamento em mapas Bing.As empresas podem escrever aplicativos para anunciar seus produtos ou para complementar os serviços on-line.Por exemplo, de bestparking.com desenvolveu um aplicativo “ estacionamento localizador ”, que ajuda você a encontrar todos os recursos de estacionamento em sua cidade usando seu banco de dados.

Para ver a aparência de um aplicativo do mapa, vá para os mapas de Bing explorar o site e clique no botão MAP APPS localizado próximo ao canto inferior esquerdo da página.A Galeria de mapa de aplicativos será aberto, mostrando os aplicativos disponíveis.Já existem muitos aplicativos de destaque na galeria e ele continua a crescer.

Neste artigo, descreverei o que é preciso para escrever um aplicativo do mapa usando o SDK do Bing mapa de aplicativo.Apresentarei é o desenvolvimento de um aplicativo de exemplo que mostra informações de chegada de barramento em tempo real em torno de King County, no estado de Washington.Esse aplicativo é inspirado por aplicativo um barramento Away popular.

O produto final

Antes que eu me aprofundar no código, let’s dê uma olhada em como será a aparência do aplicativo do mapa final.Quando ativado, se o mapa é ampliado para a área de King County, meu aplicativo mapa mostrará no painel esquerdo da lista de todas as paradas de barramento dentro da porta de visualização do mapa (consulte do Figura 1).

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

Figura 1 do OBA App mostra informações sobre o barramento no painel à esquerda e do recurso ' anotações ' na estrutura do

Cada parada de barramento possui informações sobre todos os barramentos que atende a esse limite.Clicar no hiperlink para cada parada “ horários de chegada ” exibirá no painel de segundo, que exibe as horas de chegada iminente (consulte do Figura 2).

image: Bus Arrival Times for a Particular Bus Stop

Do barramento Times de chegada de uma parada de barramento de determinado, a Figura 2

O aplicativo também coloca um pino visualmente atraente (marcado com a letra B) em cada parada de barramento no mapa.Você pode interagir com anotações para ativar um janela pop-up, de onde você pode chamar comandos comuns de uma parada de barramento específico, como Obtendo dirigindo ou movimentar as direções para ou (consulte do Figura 3) do mesmo.

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

De clicar em uma anotação mostra uma interface do usuário pop-up com informações adicionais, a Figura 3

Baixar o SDK do Bing mapa de aplicativo

Antes de começar a escrever seu primeiro aplicativo do mapa, você precisa instalar o SDK do aplicativo do mapa de Bing em connect.microsoft.com/bingmapapps de .O SDK fornece os assemblies de referência, um projeto de exemplo e documentação off-line.Além disso, como o SDK é baseado no Silverlight 4, você também precisará instalar as ferramentas de 4 do Silverlight para Visual Studio 2010, disponível em silverlight.net/getstarted/ de .

Noções básicas do mapa de aplicativo

Explore os mapas de Bing site foi criado com a extensibilidade como uma das principais prioridades.A equipe de mapas Bing queria permitir que os desenvolvedores em todo o mundo para facilmente adicionar funcionalidade que possa ser útil e que pode ser potencialmente útil para outras pessoas.Nesse sentido, um aplicativo do mapa de é um recurso concreto que faz uso dos serviços bloco de construção fornecidos pelo Centro de mapas Bing.Se você examinar o site padrão do Bing Maps, indicações sobre como chegar, recursos de pesquisa de pesquisa e localização de negócios são todos criados a partir mesmos blocos de construção.

Com esse objetivo em mente, a equipe de mapas Bing decidiu criar uma estrutura extensível para oferecer suporte ao conceito de mapa de aplicativos.Quando escritos na parte superior da estrutura, o mapa de aplicativos tirar proveito de uma abordagem de estilo de injeção de dependência para fornecer acesso à funcionalidade similar àquela encontrada no Managed Extensibility Framework (MEF).

O núcleo da estrutura é o conceito de plug-ins.Um plug-in é uma unidade de extensibilidade que permite aos desenvolvedores adicionar recursos de uma maneira fácil de manter dissociada.Ele pode ser considerado como equivalente a uma parte composto no MEF terminologia.Por meio de atributos, um plug-in declara as importações que ele precisa, bem como as exportações que deseja compartilhar.Em tempo de execução, a estrutura será resolva dependências entre os plug-ins e coincidir com as importações que as exportações do mesmo contrato.

Para escrever um aplicativo do mapa, você pode criar uma biblioteca de classes do Silverlight 4 contém exatamente uma subclasse da classe base do plug-in.Para fazer algo útil, seu plug-in será provavelmente importar vários contratos internos que permitem acessar vários serviços principais.A documentação do SDK tem uma seção que lista todos os contratos internos exportados pela estrutura.

Para fazer referência a classe de plug-in e todos os tipos de contrato interno, será necessário referenciar os assemblies fornecidos no SDK do seu projeto.Figura 4 descreve brevemente esses quatro conjuntos de módulos.

Figura 4 do assemblies de referência para um projeto de aplicativo do mapa

Nome do assembly Descrição
Microsoft.Maps.Plugins.dll Contém a classe de plug-in de base e classes de atributo de importação/exportação relacionadas.
Microsoft.Maps.Core.dll Contém todos os tipos de contrato Bing Maps fornece.
Microsoft.Maps.MapControl.Types.dll Contém os tipos necessários para trabalhar com o controle do mapa.
Microsoft.Maps.Extended.dll Contém tipos para interagir com o modo de mapa StreetSide.

Acessar o barramento de uma API de ausência

Para obter informações de chegada de barramento em tempo real, vai se estivesse fazendo use da disponíveis publicamente um barramento Away REST API (simplesmente conhecido como API do OBA para o restante deste artigo).Você encontrará detalhes sobre a API do OBA em code.google.com/p/onebusaway/wiki/OneBusAwayRestApi de .(Observe que a API é atualmente livre para uso não comercial, mas é necessário que você registre-se para uma tecla de aplicativo antes de poder acessá-lo.O código para download deste artigo, removi a chave atribuída a mim, portanto, se você deseja compilar e experimente o aplicativo por conta própria, você precisa substituí-lo por sua própria chave.)

Quando um aplicativo do Silverlight tenta acessar um serviço da Web em um domínio diferente, o runtime do Silverlight exige que o serviço explicitamente deve consentir para permitir o acesso entre domínios.Um serviço indica seu consentimento, colocando o arquivo de um clientaccesspolicy.xml ou crossdomain. XML na raiz do domínio onde o serviço está hospedado.Mais detalhes sobre os esquemas desses dois arquivos são documentados no msdn.microsoft.com/library/cc197955%28VS.95%29 de .Felizmente, a API do OBA fornece o arquivo crossdomain. XML, que permite que o meu aplicativo de mapa de chamá-la em código do Silverlight.

A solução que pode ser baixada, você verá dois projetos de biblioteca, ObaApp e ObaLib.ObaApp é o projeto principal, que contém o aplicativo do mapa de plug-in, e ele faz referência a ObaLib.ObaLib é outro projeto de biblioteca de classe que encapsula todas as classes auxiliares para se comunicar com a API do OBA.Eu fiz isso uma biblioteca separada, para que poder facilmente reutilizá-lo em diferentes projetos se eu precisar.Não entrarei em detalhes de todas as classes na biblioteca, mas você está encorajado a examinar o código-fonte para obter mais informações sobre as classes de lá.

A classe mais importante saber é a classe ObaSearchHelper, que fornece métodos convenientes e eventos para fazer consultas para a API do 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
  // ...
}

É fácil detectar o padrão usado nessa classe. Para cada ponto de extremidade do REST da API do OBA, há um método para disparar um evento correspondente para sinalizar a conclusão de que a pesquisa e de pesquisa. Os assinantes de eventos podem obter os resultados de objetos de argumento de evento.

Com essa classe útil pronto, let’s dissecam as classes principais no projeto ObaApp.

Definir a entidade do mapa

A primeira coisa que você precisa fazer ao escrever um aplicativo do mapa é definir a entidade de mapa. Esta é a definição da entidade da documentação do SDK: “ Uma entidade é um item associado a geográfica no mapa. Uma entidade de mapa pode ser um ponto, uma polilinha, um polígono ou uma sobreposição de imagem. ” O princípio simples é que, se você quiser colocar algo no mapa, você precisa uma instância da entidade para representá-lo. Em geral, você deseja criar uma subclasse de entidade para adicionar propriedades extras e lógica personalizada para as entidades. Em meu aplicativo, pois quero mostrar os locais das paradas de barramento, escrevi uma classe BusStopEntity para representar um limite de barramento. A Figura 5 mostra a classe BusStopEntity.

A Figura 5 da 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);
  }
}

Minha classe BusStopEntity expõe duas propriedades Name e StopId, que usarei posteriormente para ligação de dados a controles de interface do usuário. Esses valores provenientes de instância de BusStop subjacente. Definidas no projeto ObaLib, a classe BusStop encapsula os dados de uma parada de barramento, ele obtém da API do OBA.

O construtor, eu também definir o primitivo e as propriedades de nome. A propriedade primitiva representa o tipo (por exemplo, ponto, polígono ou polilinha) e o local do meu tipo de entidade. Defino o local para os valores de longitude e latitude da instância BusStop. Além disso, definindo a propriedade primitiva como o valor retornado do PushpinFactoryContract.CreateStandardPushpin dá a minha entidade a aparência das anotações de mapas Bing padrão. O tipo de PushpinFactoryContract fornece métodos úteis para a criação de elementos da interface do usuário comuns alfinete. Você não precisa usá-lo se você deseja criar suas próprias formas de pino personalizados. Aqui simplesmente colocar uma letra B (barramento) dentro do pino, mas você pode usar uma imagem ou qualquer UIElement.

Em meu subclasse, eu defino a propriedade Name, apesar de não ser reconhecida por outros tipos no SDK do — esses tipos simplesmente não possuam conhecimento de minha propriedade. Portanto, também defini o mesmo valor para a propriedade de dependência do nome, recupero por meio da chamada Entity.RetrieveProperty (“ nome ”, typeof(string)). Fazendo isso, eu ativar outros recursos recuperar o nome de uma entidade de barramento de parada.

O principal plug-in de gravação

Como explicado anteriormente, você precisa de uma classe derivada de plug-in para representar o aplicativo do mapa. Figura 6 mostra meu, que é adequadamente chamada de ObaPlugin. O plug-in-importa um total de seis contratos. Observe que todos os contratos fornecidos pelo Bing Maps seguem a convenção de nomenclatura da Microsoft / *. A documentação do SDK fornece descrições detalhadas de todos os contratos que podem ser importados, mostrado na do Figura 7.

Figura 6 de importações declaradas na 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

A Figura 7 de contratos importados pelo ObaPlugin

Tipo de contrato Descrição
LayerManagerContract Permite que um plug-in adicionar ou remover camadas do mapa.
PopupContract Permite que um plug-in mostrar o 
UI pop-up quando o usuário passa ou clicar em 
entities/pusphins.
ConfigurationContract Permite que um plug-in carregar dinamicamente valores de configuração do arquivo de configuração em tempo de execução.
MapContract Permite que um plug-in de controle do mapa.
PushpinFactoryContract Permite que um plug-in processar o padrão de anotações para suas entidades.
ContributorHelperContract Permite que um plug-in criar assíncrona ou colaboradores da carga de demanda. (Usarei esse auxiliar para adicionar “ driving direções ” e “ StreetSide ” colaborador links à minha janela pop-up, mais tarde).

Depois de declarar as importações, substitui o 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();
}

Esse método é chamado de exatamente uma vez depois que a instância do plug-in é construída e todas as importações declaradas foram satisfeitas. Este é o lugar perfeito para fazer qualquer trabalho de inicialização depende de contratos de importado. Se o seu plug-in possui as exportações, também precisará certificar-se de que todas as propriedades exportadas são totalmente instanciadas pelo tempo de que inicialização retorna.

Eu primeiro obter a chave de aplicativo do arquivo de configuração por meio da instância de ConfigurationContract importado e passá-lo para o construtor ObaSearchHelper. Colocando a chave de aplicativo no arquivo de configuração, pode facilmente alterá-lo a qualquer momento sem recompilar o meu projeto.

A segunda coisa a que fazer é ligar o evento TargetViewChangedThrottled da instância MapContract. Este evento é disparado sempre que o modo de exibição do mapa está prestes a alterar, por meio de programação ou por meio de interação do usuário. Como o nome sugere, o evento é acelerado internamente para que não dispara muitas vezes dentro de uma curta duração. Portanto, é um evento perfeito para considerar se deseja manter suas entidades em sincronia com o modo de exibição do mapa. No meu caso, eu chamo o método RefreshBusStops para atualizar a lista de paradas de barramento de. Esta é a definição 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();
  }
}

Aqui, eu verificar se o atual nível de zoom do mapa é pelo menos 14, em seguida, emito uma chamada ao método SearchStopsByLocation, que retornará a lista de todas as paradas de barramento dentro de um raio especificada ao redor do centro do mapa. Caso contrário, se o nível de zoom for menor do que 14, que significa que o mapa não atingiu na próxima o bastante para o nível de cidade, o que eu limpar todas as paradas de barramento.

Quando o método SearchStopsByLocation é concluída (assíncrona), ela lança o evento SearchStopsByLocationCompleted, mostrado em Figura 8 , que assinou o que eu anteriormente no método Initialize.

A Figura 8 do manipulador de eventos de 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);
}

Observe o objeto do tipo ObaLayer, que explicarei na próxima seção. É suficiente dizer que no momento, este objeto é responsável por gerenciar o conteúdo do painel à esquerda e as entidades no mapa.

Observe que eu uso um Dictionary < int BusStop >objeto para me ajudar a manter controle sobre a lista atual de paradas de barramento exibidas. Com a Ajuda desse dicionário, toda vez que eu recebo um conjunto novo de paradas de barramento da chamada de serviço, posso rapidamente determinar as paradas de novas já não são mostradas, assim como as paradas de antigas agora estão fora de visão devido à alteração de modo de exibição de mapa.

Você deve estar imaginando por que eu não apenas clear-out de todas as paradas de barramento atuais e mostrar o novo conjunto de paradas de barramento completamente. Bem, o motivo pelo qual é o desempenho. Se eu fiz isso, eu seria forçar todos os controles de pino para ser recriada, mesmo que muitas delas foram no mesmo local nas exibições do mapa antigo e novo. Pior, os usuários veria um flash curto quando as anotações foram removidas e rapidamente adicionadas novamente. Minha abordagem elimina ambas essas deficiências.

Mostrar conteúdo e o recurso ' anotações ' com uma camada

A classe de plug-in de representa o mapa de aplicativo, mas se você quiser mostrar representações de interface de usuário dele, você precisa criar camadas de . Uma camada é um conceito abstrato que permite que você coloque entidades no mapa, como anotações (polilinhas ou polígonos) e para mostrar a interface do usuário personalizada conteúdo no painel esquerdo. Opcionalmente, ele também pode colocar uma sobreposição de interface de usuário arbitrária na parte superior do mapa, mas eu não precise que para meu aplicativo. A maioria dos aplicativos tem apenas uma camada.

Se você já usou o Photoshop, você encontrará o conceito muito semelhantes às camadas do Photoshop. O botão Histórico (localizado no canto inferior esquerdo da página) mostra a lista de todas as camadas atualmente carregadas. Você pode optar por mostrar ou ocultar qualquer camada, ou você pode definir uma camada de se tornar ativo. Quando uma camada fica ativa, o elemento de painel de interface do usuário é mostrado na esquerda painel e todas suas entidades são levadas encaminhamento na pilha de z-index.

No código, uma camada é uma subclasse da classe abstrata da camada. Conforme mostrado no do Figura 9, ObaPlugin cria e gerencia uma instância da classe ObaLayer, que deriva de camada.

A Figura 9 Class 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;
  }
  ...
}

No construtor do ObaLayer, posso definir o título da minha camada, que será exibido na parte superior do painel esquerdo. Também defini a propriedade do painel para uma instância do controle de usuário BusStopsPanel, que ocupará na região do painel esquerdo inteiro se minha camada fica ativa. Propriedade de DataContext do controle de usuário é definida para uma instância ObservableCollection <Entity>.

Então, como a camada é exibida? Isso é feito por ObaPlugin conforme mostrado no do Figura 10.

De método ShowResultLayer mostra a instância ObaLayer ao usuário, a Figura 10

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

A substituição do método Activate é chamada sempre que meu aplicativo de mapa é ativado pela Galeria de aplicativos do mapa. Para mostrar minha camada, eu me referir ao tipo de LayerManagerContract que já importado anteriormente. A classe LayerManagerContract define métodos para trabalhar com camadas. Se minha camada já foi adicionada, defini-la como ativa, chamando o método BringToFront. A tentativa de adicionar que os mesmos resultados de duas vezes em uma exceção de camada.

Do Figura 8, chamei o método ObaLayer.RefreshEntities para atualizar as paradas de barramento. A Figura 11 mostra sua definição.

A Figura 11 da definição do 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 adicionar ou remover uma entidade no mapa, eu uso a propriedade de coleção Layer.Entities. E para cada novo BusStopEntity, eu chamo o método PopupContract.Register registrar-se para a interface do usuário pop-up em meu pusphin parada do barramento. O método Register aceita a entidade e um método de retorno de chamada é invocado sempre que o controle pop-up altera o estado da entidade (consulte do Figura 12).

A Figura 12 de alterar o estado de um controle pop-up

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 do retorno de chamada de pop-up, o argumento de método do tipo PopupStateChangeContext me dá acesso ao estado atual do janela pop-up e a entidade no momento na janela pop-up. Com base naqueles, posso definir o título de pop-up com o nome de parada do barramento e o conteúdo de pop-up com a propriedade BusStopEntity.BusRoutesAsString, que retorna uma lista separada por vírgulas de rotas de barramento que atende a esse determinado parar de barramento.

Se o pop-up está em estado normal, eu também adicionar três links de Colaborador para o pop-up por meio da propriedade de coleção de colaboradores — o colaborador “ horários de chegada ” mostra os horários de chegada de parada de barramento, o colaborador direções chama o recurso de orientações de indicações e o colaborador Streetside alterna para o modo de mapa de rua.

Um colaborador é representado por um hiperlink na parte inferior do controle pop-up. Ele permite que aplicativos de mapa invocar um alguns dos principais recursos dos mapas Bing. Para gerar colaboradores, chamar um dos dois métodos do tipo ContributorHelperContract: CreateAsyncContributor ou CreateDemandLoadContributor. Ambos os métodos retornam um colaborador proxy síncrona e adiar o carregamento da instância real Colaborador. A única diferença é que o CreateAsyncContributor carrega o colaborador real tão logo ela retorna, ao passo que CreateDemandLoadContributor só faz isso quando o vínculo de Colaborador do proxy é chamado pela primeira vez.

BusStopsPanel UserControl

BusStopsPanel é um UserControl, que é responsável por mostrar a lista de paradas do barramento no modo de exibição no painel esquerdo (conforme mostrado no do Figura 1). Ele contém uma instância de ItemsControl, com a propriedade ItemTemplate definida como um DataTemplate personalizado (consulte do Figura 13). Observe que eu ativar o modo de virtualização da interface do usuário para o meu ItemsControl, definindo a propriedade ItemsPanel para usar um VirtualizingStackPanel. Em geral, é uma boa prática que se aplicam a virtualização de interface do usuário ItemsControl que seu aplicativo pode carregar centenas de itens para ela.

A Figura 13 do UserControl A BusStopsPanel

<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>

Dentro do limite de barramento DataTemplate, adicionei um controle HyperlinkButton, que, quando clicado, a pesquisa para os horários de chegada do barramento correspondente do disparador interromperá:

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

Observe que sua propriedade Style é definida como um objeto da coleção StaticResource, com a chave como “ App.P2.Hyperlink ”. Bing Maps fornece um conjunto padrão de recursos da interface do usuário, como, por exemplo, estilos e ControlTemplates de controles comuns, bem como padrão cores e pincéis usados pelo Bing Maps propriamente dito. Os autores do mapa de aplicativo são incentivados a aplicar estes recursos para seus elementos de interface do usuário para que eles têm a mesma aparência nativos elementos de interface do usuário. Consulte a documentação para todos os recursos fornecidos pelo Bing mapas.

SearchArrivalTimes é um método interno da classe ObaPlugin. Ele chama o método de ObaSearchHelper.SearchArrivalTimesForStop para recuperar os horários de chegada para o limite de barramento especificado:

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

Quando a pesquisa estiver concluída, o plug-in instruirá ObaLayer para mostrar os horários de chegada no painel esquerdo.ObaLayer faz isso dinamicamente alterando suas propriedades e o título do painel.

Testando e depurando a estrutura do aplicativo

Quando terminar de codificação, você desejará testar seu aplicativo.O site de mapas Bing tem um modo de desenvolvedor que está habilitado, acrescentando um “ desenvolvedor = 1 ” consulta parâmetro na URL, como este: https://www.bing.com/Maps/explore/?Developer=1.Quando estiver no modo de desenvolvedor, você testar seu aplicativo do mapa com a “ mapa de aplicativo ferramenta de teste, ” que pode ser ativada por meio da Galeria de aplicativos do mapa do mesma.A ferramenta de teste de aplicativo do mapa permite que você selecione os conjuntos de plug-in de seu disco rígido local.Em seguida, carrega seu plug-in para o site assim como faz com que todos os plug-ins nativos.Para depurar seu código, anexe o vs.net para seu navegador ao seu aplicativo é carregado.Certifique-se de que definir o tipo de depuração de código para o Silverlight.

O mapa de aplicativo de envio

Finalmente, quando estiver satisfeito com o seu código, você pode enviar o seu aplicativo a ser publicada oficialmente no site Bing Maps.Você pode enviar um novo aplicativo e exibir o status de envios anteriores no centro da conta do Maps Bing (bingmapsportal.com ).A documentação do SDK possui instruções detalhadas sobre o envio de seu aplicativo e lista os requisitos de que seus aplicativos devem atender para ser aprovado.

Plano de ação

Até lá você tem: um aplicativo completo e em tempo real de trânsito que não exige uma grande quantidade de código.O SDK fornece os blocos de construção que tornam a escrita de uma experiência interessante e gratificante centrados no mapa de aplicativos.Eu recomendo que você baixe hoje mesmo o SDK, saiba que ela e começar a escrever seus próprios aplicativos de mapa.

Luan Nguyen trabalhou como desenvolvedor na equipe do Bing Maps (anteriormente conhecida como o Microsoft Virtual Earth) quase quatro anos.Ele era um membro da equipe de recursos do shell, que era responsável pelo shell a estrutura do site Bing Maps e o SDK do Bing mapa de aplicativo.Recentemente, ele alternou para a equipe do asp.net.

Graças aos seguintes especialistas técnicos para revisão deste artigo: Alan Paulin, De Chris Pendleton , de Dan Polivy e de Greg Schechter