O objetivo deste artigo é mostrar o uso da API de GPS no Windows Phone 8.1, assim como mostrar a localização no controle de mapa, tudo é claro com a linguagem Visual C# 5. Usar GPS se tornou corriqueiro em diversas aplicações, pois praticamente todo dispositivo (celular e tablet) vem com essa funcionalidade, e integrá-la à aplicação é muito mais fácil do que você imagina. O código que mostrarei neste artigo pode ser usado nas versões 7.5, 8 e 8.1 do Windows Phone.
Se você quiser integrar a API do Bing, que é nativa, diretamente com a sua aplicação, leia este artigo, e este outro que acho muito importante para integrar uma base de dados SQL Server com o recurso de mapas. Com isso, você poderá integrar dados armazenados em uma base de dados ou requisitar dados de um serviço e mostrar no mapa os devidos pontos. Quando falo sobre dados, refiro-me à latitude e à longitude – é disso que um mapa necessita. Então, vamos ao projeto em si. Neste projeto, usarei o Visual Studio 2013 Ultimate com o Update 2 instalado.
Os pré-requisitos para este artigo são conhecimento básicos de C# e Visual Studio .NET 2013 Update 2.
Projeto Windows Phone
Já que faremos passo a passo, abra o Visual Studio 2013, selecione a opção File / New / Project ou CTRL + SHIFT + N ou, na janela inicial, clique em New Project. Conforme a figura 1, selecione Visual C# / Store Apps / Windows Phone Apps / Blank App (Windows Phone Silverlight). Em Name, digite GPS_Mapa_MSDN e, no Location, você pode gravar onde desejar.

Clique no botão OK, e o VS solicita o Target do OS do Windows Phone, conforme a figura 2. Selecione Windows Phone 8.1 – assim, o projeto já é criado com o que há de mais novo.

Clique no botão OK e deixe que o Visual Studio crie o projeto. A página MainPage.xaml é a inicial, que já aparece aberta. Todas as referências do XAML estão mostradas nas primeiras linhas, assim como a estrutura inicial sugerida pelo template. Como teremos um mapa nessa página, e é necessário espaço suficiente para exibi-lo. A primeira coisa a fazer é comentar este bloco de códigos a seguir, que já vem com o template.
<!--TitlePanel contains the name of the application and page title--><!-- <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/> <TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel>-->
Pergunta: Renatão, posso deixar essas linhas para colocar o título para que o usuário veja onde está? Sim, pode, mas eu prefiro uma tela mais limpa quando exibo mapas, senão o usuário irá desistir de ter que navegar no mapa num tamanho muito pequeno de tela, isso desanima qualquer um.
A seguir, como vamo lidar com GPS, vamos criar a seguinte estrutura de controles para mostrar a latitude e a longitude. Só que o próximo controle disponível chamado ContentPanel é um Grid, então basta trocá-lo para um StackPanel e acrescentar uma orientação Vertical. Dentro deste, adicione um outro StackPanel Vertical com dois TextBlocks, conforme códigos a seguir. Veja que defini as propriedades Style e Foreground conforme os recursos (StaticResource) do Windows Phone. Claro que você pode alterar para qualquer outro que achar mais adequado.
<StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" Orientation="Vertical"> <StackPanel Orientation="Vertical"> <TextBlock x:Name="StatusTextBlock" Text="serviço localização desligado" Style="{StaticResource PhoneTextTitle2Style}" Foreground="{StaticResource PhoneAccentBrush}" /> <TextBlock x:Name="DadosTextBlock" Text="latitude/longitude" Style="{StaticResource PhoneTextTitle2Style}" Foreground="{StaticResource PhoneAccentBrush}" /> </StackPanel> </StackPanel>
E o mapa? O mapa é um controle existente na Toolbox, então localize o controle Map na toolbox e arraste-o logo após o TextBlock chamado DadosTextBlock. Será adicionada a seguinte linha ao XAML, e aproveite e já configure as propriedades x:Name (nome do controle), ZoomLevel (Zoom default para exibir o mapa) e Height (altura).
<maps:Map x:Name="mapa" ZoomLevel="10" Height="602"/>
Por que foi adicionado o <maps:Map />? Essa notação faz referência ao namespace que é inserido automaticamente na lista no início da página, para que o controle possa ser inicializado e usado, sendo:
xmlns:maps="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"
A seguir, precisamos criar a barra de menu da aplicação, que conterá 3 botões e 4 opções de menus. Insira o bloco de códigos XAML a seguir logo abaixo do fechamento da tag do bloco shell:SystemTray.IsVisible=”True”>. Veja que para os 3 ícones estou usando imagens (png) que você pode baixar da Internet ou criar as suas próprias. Observe que o ApplicationBar está configurado para mostrar tudo (IsVisible=True) e que contém menus ativos (IsMenuEnabled=True).
<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"> <shell:ApplicationBarIconButton IconUri="/Assets/low.png" Text="Baixa" Click="Baixa_Click"/> <shell:ApplicationBarIconButton IconUri="/Assets/high.png" Text="Alta" Click="Alta_Click"/> <shell:ApplicationBarIconButton IconUri="/Assets/stop.png" Text="Parar" Click="Parar_Click"/> <shell:ApplicationBar.MenuItems> <shell:ApplicationBarMenuItem Text="Rua" Click="Rua_Click"/> <shell:ApplicationBarMenuItem Text="Aerio" Click="Aerio_Click"/> <shell:ApplicationBarMenuItem Text="Híbrido" Click="Hibrido_Click"/> <shell:ApplicationBarMenuItem Text="Terra" Click="Terra_Click"/> </shell:ApplicationBar.MenuItems> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar>
Note na figura 3 como está a tela com o layout definido até o momento.

Cabe ressaltar que cada opção do ApplicationBar, seja um ícone ou menu, contém o evento Click do objeto, ou seja, para cada uma dessas opções, você deverá assinar o evento. Pronto, salve o projeto e pressione F7 para exibir o código C#. A primeira coisa a fazer é referenciar os dois namespaces a seguir, os quais nos dão acesso à manipulação de serviços de localização e ao controle mapa.
using System.Device.Location; using Microsoft.Phone.Maps.Controls;
A seguir, logo abaixo da declaração da classe, digite as duas linhas para referenciar a classe GeoCoordinateWatcher na variável watcher, que nos dá acesso a todo o serviço de localização, e crie a variável texto do tipo string.
private void Baixa_Click(object sender, EventArgs e) { texto = "força mínima"; IniciarLocalizacao(GeoPositionAccuracy.Default); } private void Alta_Click(object sender, EventArgs e) { texto = "força total"; IniciarLocalizacao(GeoPositionAccuracy.High); }
Como esse evento IniciarLocalizacao ainda não existe, crie-o. Para isso, clique no nome do evento a ser criado e dê um CTRL + Ponto (.) + ENTER. O bloco de código a seguir recebe um argumento, que é o geoPositionAccuracy, mostra o texto “iniciando força mínima” ou “iniciando força total” no TextBlock StatusTextBlock. Depois, inicializa o objeto watcher de acordo com o parâmetro passado (Default ou High) e define a distância mínima de 20 metros conforme a posição é alterada (evento PositionChanged que veremos depois). Duas coisas importantes que você não pode deixar de setar são os eventos StatusChanged e PositionChanged, os quais pertencem ao objeto watcher. O primeiro controle é o status do GPS, e o segundo é o que ficará alerta a qualquer alteração de posição. Sendo assim, já insira o handler para ambos. A dica na digitação é que quando digitar o += já pressione o TAB (2 vezes) logo em seguida; assim, o respectivo evento é criado automaticamente. Ao final, o evento Start é disparado.
private void IniciarLocalizacao(GeoPositionAccuracy geoPositionAccuracy) { StatusTextBlock.Text = "iniciando " + texto; watcher = new GeoCoordinateWatcher(geoPositionAccuracy); watcher.MovementThreshold = 20; watcher.StatusChanged += watcher_StatusChanged; watcher.PositionChanged += watcher_PositionChanged; watcher.Start(); }
Alteração do status do GPS
O status do GPS pode ser: desabilitado, inicializando, sem dados ou pronto. Para cada opção, é importante avisar o usuário, para que ele saiba o que está acontecendo. O código do evento StatusChanged recebe como argumento o objeto sender e os eventArgs, conforme o código a seguir. Sendo assim, vamos criar um delegate assíncrono para disparar o evento a ser criado chamado TrocarStatusChanged, contendo um swtich para cada estado do GPS. Dessa forma, como será um delegate assíncrono, ele fica o tempo todo em alerta verificando o GPS, e quando o status mudar, ele dispara o evento para exibir o respectivo texto ao usuário. Quando você criar o evento TrocarStatusChanged, veja que ele é um void.
void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e) { Deployment.Current.Dispatcher.BeginInvoke(() => TrocarStatusChanged(e)); } void TrocarStatusChanged(GeoPositionStatusChangedEventArgs e) { switch (e.Status) { case GeoPositionStatus.Disabled: StatusTextBlock.Text = "localização não suportada neste dispositivo"; break; case GeoPositionStatus.Initializing: StatusTextBlock.Text = "inicializando o serviço " + texto; break; case GeoPositionStatus.NoData: StatusTextBlock.Text = "dados indisponíveis " + texto; break; case GeoPositionStatus.Ready: StatusTextBlock.Text = "recebendo dados " + texto; break; default: break; } }
Alteração da posição do GPS
Quando se utilizam os serviços do GPS, presume-se que ele vai adquirir novas coordenadas a cada momento, portanto é preciso ficar atento a cada alteração. Para isso, crie o evento a seguir, que é um delegate assíncrono que irá chamar o evento TrocarPositionChanged para capturar a nova latitude e longitude, informar ao usuário e mostrar no mapa.
Aqui cabe uma observação importante quanto ao uso do mapa da Nokia. Enquanto estamos no ambiente de desenvolvimento, não é preciso ter um appID e um Token, o seu mapa funcionará sem problemas. Mas, no momento que for distribuir a aplicação na lojinha, aí sim, você precisa entrar no site da MS Store, registrar a sua aplicação, pedir para gerar um Token e, quando este estiver gerado, é o que você deverá adicionar às linhas comentadas que deixei de propósito no código a seguir.
void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e) { Deployment.Current.Dispatcher.BeginInvoke(() => TrocarPositionChanged(e)); } void TrocarPositionChanged(GeoPositionChangedEventArgs<GeoCoordinate> e) { DadosTextBlock.Text = string.Format("lat: {0:0.000} / long: {1:0.000}", e.Position.Location.Latitude, e.Position.Location.Longitude); //MapsSettings.ApplicationContext.ApplicationId = "appID"; //MapsSettings.ApplicationContext.AuthenticationToken = "AuthenticationToken"; mapa.Center = new GeoCoordinate(e.Position.Location.Latitude, e.Position.Location.Longitude); }
Agora que já temos os delegates para ficar observando as alterações de Status e posição, digite o código para o botão Parar, conforme a seguir.
private void Parar_Click(object sender, EventArgs e) { if (watcher != null) watcher.Stop(); StatusTextBlock.Text = "sem serviço de localização"; DadosTextBlock.Text = string.Empty; }
Configuração do manifesto
Como esta é uma aplicação que usará o serviço de localização, é preciso configurar o manifesto. Portanto, abra o arquivo WMAppManifest.xml e, na guia Capabilities, marque o checkbox ID_CAP_LOCATION, conforme a figura 4. Em seguida, salve a aplicação.

Tipos de visões do mapa
A maioria dos mapas utiliza recurso de mostrar as imagens de diferentes visões, e como o nosso menu já está preparado para tal funcionalidade, resta-nos implementar o código a seguir. No geral, essa funcionalidade é tão simples que basta configurar o Enum da propriedade CartographicMode.
private void Rua_Click(object sender, EventArgs e) { mapa.CartographicMode = MapCartographicMode.Road; } private void Aerio_Click(object sender, EventArgs e) { mapa.CartographicMode = MapCartographicMode.Aerial; } private void Hibrido_Click(object sender, EventArgs e) { mapa.CartographicMode = MapCartographicMode.Hybrid; } private void Terra_Click(object sender, EventArgs e) { mapa.CartographicMode = MapCartographicMode.Terrain; }
Lidar com problemas de memória em qualquer aplicação não é fácil, e deixar coisas pendentes não é uma boa prática. Como atribuímos o handler para dois eventos do watcher no IniciarLocalizacao, sobrescreva o evento OnNavigateFrom com o código a seguir para desmarcar esses dois handlers invocados anteriormente. Isso é uma boa prática e fundamental para não dar problemas de memory leak ou conflitos desnecessários. O OnNavigateFrom ocorre quando a aplicação é suspensa ou fechada.
protected override void OnNavigatedFrom(NavigationEventArgs e) { watcher.StatusChanged -= watcher_StatusChanged; watcher.PositionChanged -= watcher_PositionChanged; base.OnNavigatedFrom(e); }
Pronto, todos os códigos estão prontos. Compile a aplicação e certifique-se de que está compilado 100% com sucesso. Pressione F5 para executar a aplicação no emulador do Windows Phone 8.1. Se você estiver utilizando um proxy e não mostrar o mapa, é preciso configurar a rede para que a máquina virtual enxergue a sua rede, afinal o emulador é uma máquina virtual.
Assim que a aplicação abrir no emulador, clique no primeiro ou segundo ícones para ativar a localização. Uma excelente opção é clicar no ícone Tools (>>) para exibir as ferramentas adicionais. Na guia Location, digite o nome da cidade e marque um ponto com o mouse para que o mapa no celular seja mostrado, assim como a latitude e a longitude. Na figura 5, digitei a cidade Seattle e marquei um determinado ponto.

Agora, alterei para a cidade de Florianópolis e marquei um ponto. Na aplicação, selecione o menu com vista aérea, conforme a figura 6. Nos ícones do emulador, há um ícone com um indicador, que deve utilizar para dar o zoom no mapa do emulador.

Já que programamos os códigos, fique à vontade para selecionar os demais tipos de visões e identificar qual é a mais adequada para você, conforme a figura 7.

Você pode colocar breakpoints nos códigos para identificar exatamente o que se passa quando ocorre uma alteração na mudança de posição ou alteração do status do GPS.
Conclusão
O uso de mapas integrados à aplicação tem se tornado comum em diversas áreas. Imagine aplicações de rastreamento de encomendas ou ainda entregas de mercadorias, ou seja, o horizonte que podemos ter nessa área é muito amplo. E, do ponto de vista de implementação de códigos visto neste artigo, facilita muito para o desenvolvedor que deseja adicionar mapas para enriquecer a aplicação.
Agradeço a oportunidade de poder compartilhar o conhecimento com todos. Qualquer dúvida e preparação de times de desenvolvimento, por favor me contate.