Com a vinda do Windows Phone 7 e o já apresentado Windows 8 é notável que a interface Metro será uma tendência entre as soluções e produtos Microsoft, criando um novo paradigma em UX (User Experience). Dominarmos este novo ambiente é muito interessante para o desenvolvimento de aplicações panorâmicas, criando telas que deslizam durante a utilização do aplicativo.

A vontade de desenvolver soluções com exibição de dados com atualização em tempo real cresce, não apenas pela necessidade de termos informações Just In Time, mas também pela ambição dos desenvolvedores. É aí que entra a necessidade de utilização de soluções para sincronização de objetos de dados com informações remotas com pouca codificação. A coleção ObservableCollection veio com esse propósito e será bem aplicado neste trabalho.

Sobre a classe ObservableCollection

Este recurso nos permite persistir uma coleção de dados dinamicamente. Mas a grande característica desta classe é que esta trabalha com notificações quando itens são adicionados, removidos, ou quando se qualquer ítem de sua coleção é atualizado. Essas notificações ocorrem de forma implícitas. Isso quer dizer que controles que suportam um DataSource tipo ObservableCollection poderão se auto-atualizar quando receberam notificações de suas fontes.

Isso é possível pois a classe ObservableCollection implementa, dessa forma, a Interface INotifyCollectionChanged, na qual define o evento CollactionChanged. Com isso WebControls podem assinar a este evento e assim serem notificados quando um registro é adicionado, removido, substituído, movido ou alterado dentro da coleção ou mesmo se todo seu conteúdo for substituído.

Importante já adiantar que para execução deste projeto foi utilizado o Json.NET (por James Newton-King). Seus binários e fontes podem ser baixados no CodePlex.

Criando um projeto Windows Phone Panorama

Primeiramente vamos criar um novo projeto para WP7 Panorama. Para isso vá em File > New Project > Silverlight for Windows Phone > WP7 Panorama with Caliburn.Micro como na imagem abaixo:

Novo Projeto Windows Phone

Figura 01. Criando um projeto WP7 Panorama

Caso seu Visual Studio não exiba o template WP7 Panorama, nesta mesma janela, vá em Online Templates e busque por WP7 Panorama e instale-o antes de prosseguir.

Caliburn.Micro é um pequeno, mas poderoso, framework, desenhado para construir aplicações por todas Plataformas Xaml. Com um forte suporte ao MVVM e outros conhecidos padrões UI, Caliburn.Micro irá te permitir criar seus soluções rapidamente, sem a necessidade de sacrificar sua qualidade de códigos ou testabilidade.

Agora execute o projeto (F5) uma vez e veja que bacana ver uma aplicação Windows Phone com visual metro rodando no emulador.

Adicionando um Web Reference ao projeto

Precisamos agora adicionar a referência web do webservice que nossa aplicação irá consumir. Para isso basta clicar com botão direto no nome do projeto e depois em Add Service Reference e a janela abaixo irá aparecer:

Add Service Reference

Figura 02 – Adicionando um Service Reference

No campo Address, preencha com a URL do webservice que será consumido. Caso ele esteja já publicado na web, provavelmenter será um endereço diferente de localhost. Depois pressione o botão “Go”. Tendo sucesso na conexão, na caixa Services irá ser mostrado os serviços do webservice. Então basta selecionar o qual irá utilizar e, no campo Namespace dar um nome para o namespace no qual o webservice ficará referenciado. Após clicar em OK, deverá ficar como na imagem abaixo:

Referencia no Projeto

Figura 03 – Webservice referenciado no projeto

Preparando a camada de View

Vamos preparar a camada de View para exibirmos os dados que virão do webservice. No arquivo MainPage.xaml, vamos trocar o conteúdo do LayoutRoot pelo código abaixo:

[html]
<!–Panorama item one–>
   <controls:PanoramaItem Header="Zulu GMT">
     <ListBox Margin="0,0,-12,0" ItemsSource="{Binding TimeZoneGMT}">
       <ListBox.ItemTemplate>
         <DataTemplate>
           <StackPanel Margin="0,0,0,17" >
             <TextBlock Text="{Binding TimeZone}" TextWrapping="Wrap" />
             <TextBlock Text="{Binding Date}" TextWrapping="Wrap" Margin="12,-6,12,0" />
             <TextBlock Text="{Binding Hour}" TextWrapping="Wrap" Margin="12,-6,12,0" />
           </StackPanel>
         </DataTemplate>
       </ListBox.ItemTemplate>
     </ListBox>
   </controls:PanoramaItem>

<!–Panorama item two–>
   <controls:PanoramaItem Header="Brasilia">
     <ListBox Margin="0,0,-12,0" ItemsSource="{Binding TimeZoneBRA}">
       <ListBox.ItemTemplate>
         <DataTemplate>
           <StackPanel Margin="0,0,0,17" >
             <TextBlock Text="{Binding TimeZone}" TextWrapping="Wrap" />
             <TextBlock Text="{Binding Date}" TextWrapping="Wrap" Margin="12,-6,12,0" />
             <TextBlock Text="{Binding Hour}" TextWrapping="Wrap" Margin="12,-6,12,0" />
           </StackPanel>
         </DataTemplate>
       </ListBox.ItemTemplate>
     </ListBox>
   </controls:PanoramaItem>
[/html]

Pela definição, vamos ter duas telas, dentro do design panoramico, uma mostrando a atual hora GMT e outra com o horário de Brasília. Assim poderemos rolar entre as duas telas e acompanhar suas atualizações.

Definindo classes ObservableCollection

Chegamos ao principal assunto de nossa aplicação. Ao criarmos nossos modelos para serem consumidos por “observadores”, teremos o controle que qualquer alteração vinda de nossa fonte de dados (webservice>) será imediatamente projetada para a tela da aplicação.

Como dito no início, a classe ObservableCollection implementa a interface INotifyCollectionChanged, portando vamos criar uma classe tipo Caliburn.Micro.PropertyChangedBase afim de ser consumida por um “observador”. Crie, então, um arquivo de classe em /Model/TimeZoneModel.cs com o fonte abaixo:

[csharp]
using Caliburn.Micro;
public class TimeZoneModel : PropertyChangedBase
{
     private int _TimeZone;
     public int TimeZone
     {
       get { return _TimeZone; }
       set
{
         if (value != _TimeZone)
         {
           _TimeZone = value;
           NotifyOfPropertyChange(() => TimeZone);
         }
       }
     }

private string _Date;
     public string Date
     {
       get { return _Date; }
       set
       {
         if (value != _Date)
         {
           _Date = value;
           NotifyOfPropertyChange(() => Date);
         }
       }
     }

private string _Hour;
     public string Hour
     {
       get { return _Hour; }
       set
       {
         if (value != _Hour)
         {
           _Hour = value;
           NotifyOfPropertyChange(() => Hour);
         }
       }
     }
   }
[/csharp]

Note o método chamado NotifyOfPropertyChange(), este método é o notificador do nosso modelo. Como podemos ver, quando alguma propriedade sofrer alteração, iremos gerar uma notificação que este teve seu valor atualizado. Isso fará com que o objeto de exibição na tela do aplicativo atualize essa informação na tela.

Não podemos esquecer de alterarmos a classe Bootstrapper.cs, no método Configure(), e vincularmos nossa nova classe à requisições:

[csharp]container.PerRequest<TimeZoneModel>();[/csharp]

Vamos agora trabalhar na camada de ViewModel, primeiramente vamos excluir a classe ViewModels/ItemViewModel.cs que faz parte apenas do template (lembre-se de excluir também as sua referência no Bootstrapper.cs). Depois vamos trabalhar em cima da classe ViewModels/MainPageViewModel.cs.

Lembrando que nossa aplicação Windows Phone irá consumir um Webservice, e que este irá retornar uma estrutura de dados (no caso, tipo Json), teremos então que converter essa estrutura de dados em algo mais aceito pelo .NET. Como estamos utilizando uma solução chamada Json.NET, esta nos oferece alguns conversores de estrutura de dados Json para classes serializaveis.

O Webservice em questão (leia mais sobre ele pelo links ao final do artigo) irá retornar uma estrutra como abaixo:

[{“TimeZone”:0,”Date”:”2012-04-11″,”Hour”:”14:27:19″},{“TimeZone”:-3,”Date”:”2012-04-11″,”Hour”:”11:27:19″}]

Então temos que criar uma estrutura de classes que reflita essa estrutura Json. Para isso vamos utilizar uma ferramenta online chamada json2csharp.com para gerar nossas classes que ficará assim:

[csharp]
// Já renomeei de RootObject para TimeZoneData
   public class TimeZoneData
   {
     public int TimeZone { get; set; }
     public string Date { get; set; }
     public string Hour { get; set; }
   }
[/csharp]

Vamos declarar objetos globais com os observadores, definindo esta como tipo TimeZoneModel. Vamos também já declarar nosso webservice client para consumirmos da fonte de dados, e também vamos criar um cronometro para disparar a atualização da tela periodicamente.

[csharp]
public ObservableCollection<TimeZoneModel> TimeZoneGMT { get; private set; }
public ObservableCollection<TimeZoneModel> TimeZoneBRA { get; private set; }

public MyJsonWS.json_wsSoapClient jsonClient;
public System.Windows.Threading.DispatcherTimer dt;
[/csharp]

Agora, no método construtor da classe, vamos instanciar os objetos globais declarados, e também delegar um método ao evento de conclusão da chamado ao webservice.

[csharp]
public MainPageViewModel()
{
     this.TimeZoneGMT = new ObservableCollection<TimeZoneModel>();
     this.TimeZoneBRA = new ObservableCollection<TimeZoneModel>();

this.jsonClient = new MyJsonWS.json_wsSoapClient();
jsonClient.GetHourUTCCompleted += new System.EventHandler<MyJsonWS.GetHourUTCCompletedEventArgs>(jsonClient_GetHourUTCCompleted);

dt = new System.Windows.Threading.DispatcherTimer();
     dt.Tick += new System.EventHandler(dt_Tick);
     dt.Interval = new System.TimeSpan(0, 0, 5); // dispara a cada 5 segundos
     dt.Start();
}
[/csharp]

A cada tick do nosso crometro, este deve realizar uma nova chamado ao webservice afim de atualizar os dados da tela. Então o método abaixo apenas dispara uma chamada assíncrona ao webservice, e o método jsonClient_GetHourUTCCompleted vai aguardar o retorno.

[csharp]
protected void dt_Tick(object sender, System.EventArgs e)
{
jsonClient.GetHourUTCAsync(-3);
}
[/csharp]

Só precisamos agora tratar os dados JSON que estão vindo do webservice. Vamos serializa-los em uma coleção para que os observadores sejam notificados e atualizem a tela da aplicação.

[csharp]
protected void jsonClient_GetHourUTCCompleted(object sender, MyJsonWS.GetHourUTCCompletedEventArgs e)
{
     List<TimeZoneData> TimeZoneList = Newtonsoft.Json.JsonConvert.DeserializeObject<List<TimeZoneData>>(e.Result);
     foreach (TimeZoneData item in TimeZoneList)
     {
       if (item.TimeZone == 0)
       {
         TimeZoneGMT.Clear();
         TimeZoneGMT.Add(new TimeZoneModel()
         {
           TimeZone = item.TimeZone,
           Date = item.Date,
           Hour = item.Hour
         });
       }
       else if (item.TimeZone == -3)
       {
         TimeZoneBRA.Clear();
         TimeZoneBRA.Add(new TimeZoneModel()
         {
           TimeZone = item.TimeZone,
           Date = item.Date,
           Hour = item.Hour
         });
       }
     }
   }
[/csharp]

Pronto! Basta agora executarmos o projeto Windows Phone e vermos nossa aplicação, com interface Metro/Panorama, consumindo um webservice que retorna dados em JSON, funcionando perfeitamente e atualizando seus dados a cada 5 segudos.

ss2     ss1

Figura 04 – Screenshots da aplicação Metro

Conclusão

Neste artigo vimos que, para aplicativos Windows Phone 7 que não exisgem recursos visuais, a interface Metro atende muito bem. Ela é fácil de desenvolver e muito agradável de navegar/utilizar. Implementamos o consumo de dados externos via webservice e notamos que, neste ponto, não ouve modificações em sua aplicação do ASP.NET para Silverlight (WP). O que foi muito bom pois não houve necessidade de reaprendizado. Aplicamos também técnicas de auto-refresh utilizando um TimeDisptcher para disparar a chamada ao webservice periodicamente. E finalmente viamos a aplicação da classe ObservableCollections que é muito eficiente para gerir atualização de informações da tela do aplicativo, dispensando vários controle entre as camadas de Modelo e de Visualização.

[mc4wp_form id="3070"]

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts

Windows Platform

Aumentando a oportunidade de monetização para desenvolvedores de Windows Phone

Segue abaixo um email que eu, e muitos outros desenvolvedores, recebi da Microsoft sobre oportunidade de ganhar dinheiro com Windows Phone. Traduzido por Bing Translator. 🙂 Aumentando a oportunidade de monetização para desenvolvedores de Windows Read more…

Eventos

Visual Studio Summit 2012

Visual Studio Summit é um evento nacional reunindo desenvolvedores de todo o Brasil focados na plataforma do Visual Studio. Nesta oportunidade palestrei sobre desenvolvimento para Windows Phone 8 com Visual Studio 2012. Foi muito bacana Read more…