15 de nov. de 2011

Twitter + Silverlight ou WPF

Vamos fazer um cliente de Twitter???

Vamos!

Ebaaa...

image

Ok ok, comemorações a parte vamos iniciar.

A ideia aqui é usar a API do Twitter, fazendo simples requisições web, e aproveitar o potencial do XAML, a linguagem de interface por trás do Silverlight (inclusive do Windows Phone) e do WPF.

Então crie uma aplicação utilizando uma dessas tecnologias chamada de “MeuClienteDeTwitter”.

No exemplo foi utilizado WPF. Nossa UI ficará da seguinte maneira:

clip_image002

No “.xaml” principal/inicial (no caso do WPF o “MainWindow.xaml”), desenhe uma tela, arrastando os controles da Toolbox para a tela, com os seguintes controles:

  • TextBlock: Ao topo servindo de título para a aplicação. Altere a propriedade “Text” (para definir o valor do mesmo) e as propriedades de fonte, para deixar esse texto mais destacado. Esse controle funciona como uma Label do ASP.NET ou Windows Forms.
  • TextBox: Caixa de texto editável. Defina o nome dela como “txtUsuario”, acompanhe na imagem a seguir:
    clip_image004
  • Button: Botão para fazer a requisição e listar os tweets do usuário informado. Defina seu nome como “btnCarregar”.
  • ListBox: Lista de itens. Montaremos um layout para os itens que listaremos. Por hora nomeie-o como “lstConteudo”, e deixe seu fundo transparente, como na imagem abaixo:
    clip_image006

Curiosidade: O controle Label existe tanto no WPF como no Silverlight. Mas ele é um ContentControl, o que significa que ele pode conter “qualquer coisa” dentro delae não ficando limitado somente a texto puro e simples. Podemos adicionar um vídeo e imagem dentro da mesma Label, por exemplo. Como nesse exemplo queremos apenas texto para o título, optei pelo TextBlock.

Uma coisa importante quando definimos layout de telas com XAML é ficar atento ao painel de layout. Pois todos os controles são aninhados e organizados em um ou mais painéis. Há vários painéis, cada um com uma forma de organizar o layout diferente. Nesse caso, todos esses controles ficam dentro de uma Grid.

Essa Grid “não tem nada haver” com as conhecidas “DataGrids”, que montam tabelas com linhas e colunas proveniente de uma coleção de dados.

A Grid do XAML é um painel que se orienta por distancia das margens. Por exemplo: se colocarmos um botão em uma Grid, e definirmos ele com uma margem de 20 pixels na esquerda e 20 pixels na direita, não interessa o tamanho da janela ou o quanto ela for redimensionada, o controle se adaptará para manter a distancia das margens, sempre em 20 pixels próximo as bordas laterais.

A Grid pode ser dividida, criando bordas internas. Nesse exemplo, foi definida uma borda logo abaixo do botão e do campo de texto, para separar a ListBox dos demais controles. Assim, após colocar a ListBox na parte inferior, defini as margens dela como zero para todos os lados, logo ela acompanhará o tamanho da janela tanto em largura como em altura.

Bem, o intuito aqui não é ficar discutindo sobre esses painéis, em outra oportunidade eu falo mais dos mesmos.

Vejamos como ficou o XAML então:

<Window x:Class="MeuClienteDeTwitter.MainWindow"
        xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="484" Width="385">
    <!--Definindo o fundo em gradiente da janela-->
    <Window.Background>
        <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
            <GradientStop Color="LightBlue" Offset="0" />
            <GradientStop Color="White" Offset="1" />
        </LinearGradientBrush>
    </Window.Background>
    <Grid>
        <!--Definindo as linhas da grid para o layout.
        O "*" representa o tamanho que sobrar da jenala,
        após utilizar os 80 da linha de cima-->
        <Grid.RowDefinitions>
            <RowDefinition Height="80" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
       
        <Label Content="Meu Cliente de Twitter" Height="28" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" FontWeight="Bold" FontSize="16" FontFamily="Verdana" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="12,46,0,0" Name="txtUsuario" VerticalAlignment="Top" Width="213" />
        <Button Content="Carregar o Twitter" Height="23" HorizontalAlignment="Left" Margin="231,46,0,0" Name="btnCarregar" VerticalAlignment="Top" Width="124" Click="btnCarregar_Click" />
       
        <ListBox Grid.Row="1" Name="lstConteudo" BorderBrush="{x:Null}" Background="{x:Null}">
            <!--Template que define o layout de cada item da ListBox-->
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <!--Perceba que foi utilizado um outro painel para definir o layout-->
                    <StackPanel Orientation="Horizontal" Height="132">
                        <Image Source="{Binding UrlFoto}" Height="73" Width="73" VerticalAlignment="Top" Margin="0,10,8,0" />
                        <StackPanel Width="370">
                            <TextBlock Text="{Binding Usuario}" Foreground="#FFC8AB14" FontSize="28"/>
                            <TextBlock Text="{Binding Conteudo}" TextWrapping="Wrap" FontSize="23"/>
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

Para fazer o fundo em gradiente, utilizamos o LinearGradientBrush com duas cores definidas para a Janela.

A primeira linha da Grid, que separa a ListBox dos demais controles do “cabeçalho”, tem 80 pixels de altura, o restante, definido como “*”, fica para a segunda linha que é onde está a ListBox.

Agora vem uma parte importante, a definição do layout dos itens que forem carregados no ListBox. Para isso temos que criar um painel de Layout, dentro do template de dados da ListBox.

Nesse caso o painel de layout utilizado foi o StackPanel, ou painel empilhador. Ele empilha os controles, um sobre o outro, seja na vertical ou na horizontal.

Dentro desse painel, colocamos um controle Image, para exibir a foto do usuário, com altura e largura de 73 pixels. Colocamos também dois TextBlock, um para o nome do usuário, com fonte um pouco maior, e outro para o tweet em si, com a quebra de linha ativada (propriedade “TextWrapping="Wrap"”).

Uma outra curiosidade: se você vem do desenvolvimento Windows Forms e quer uma maneira de organizar layout semelhante aos “bons e velhos” formulários, opte pelo painel chamado Canvas.

Ao analisar o XAML uma coisa deve estar te deixando cmo a pulga atrás da orelha: O que são aqueles “bindings”.

image

O pessoal do ASP.NET deve até desconfiar.

Bem, os bindings são definições de vinculo. Ou seja, nesse caso, passaremos uma lista de objetos para o ListBox. Esses objetos serão do tipo ItemTwitter, que criaremos mais adiante. Ou melhor, vamos cria-lo agora. Clique com o botão direito no projeto > Add > Class. Veja na imagem abaixo:

clip_image008

O nome dela será “ItemTwitter”, o código fonte está abaixo:

namespace MeuClienteDeTwitter
{
    public class ItemTwitter
    {
        public string UrlFoto { get; set; }
        public string Usuario { get; set; }
        public string Conteudo { get; set; }
    }
}

Basicamente três propriedades string estão definidas.

Voltando ao binding, quando passarmos para o ListBox uma lista do tipo ItemTwitter, para cada objeto da lista será criado um item no ListBox. Mas como vincular o layout com as informações dos itens da lista? Definindo um binding no controle e propriedade desejados. No caso da foto, colocaremos no controle Image, na propriedade Source (pois vincularemos a URL da foto do usuário). Nos TextBlocks a propriedade de vinculo será a Text.

No futuro falarei especificamente de binding.

Faltou definir a codificação para tudo funcionar. Então volte para o modo de desing e dê um duplo click no botão, assim será criado o evento click do mesmo.

Em seu click definiremos o seguinte código:

using System;
using System.Linq;
using System.Net;
using System.Windows;
using System.Xml.Linq;
 
namespace MeuClienteDeTwitter
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
       
        // -> Método do evento de click do botão para carregar os tweets.
        private void btnCarregar_Click(object sender, RoutedEventArgs e)
        {
            // -> Criamos um objeto que fará uma requisição web para a API do Twitter.
            var requisicao = new WebClient();
 
            // -> Concatenando o nome do usuário digitado na txtUsuario na URL da API do Twitter.
            var url = string.Format("
http://api.twitter.com/1/statuses/user_timeline.xml?screen_name={0}", txtUsuario.Text);
 
            /*
             -> Faremos a requisição web de forma assincrona, ou seja,
             * a requisição é disparada a aplicação não ficará travada até ela responder.
             * Mas quando ela responder, deve responder para a aplicação com um evento.
             * Então temos que definir o evento que ela responderá "requisicao_DownloadStringCompleted".
             * Agora podemos fazer a requisição assincrona, passando a URL da API, atravéz da classe URI.
             */
            requisicao.DownloadStringCompleted += new DownloadStringCompletedEventHandler(requisicao_DownloadStringCompleted);
            requisicao.DownloadStringAsync(new Uri(url));
        }
 
        void requisicao_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            // -> Todo o retorno do prossessamento da requisição virá na variável "e".
           
            // -> Verificamos se houve algum erro.
            if (e.Error != null)
                return;
 
            // -> o Retorno da requisição é um XML. Teste no seu navegador para averiguar.
            //      Então fazemos um parse nele para utilizar o LINQ.
            var tweets = XElement.Parse(e.Result);
 
            // -> Usando o LINQ, tranformamos os nós do XML em uma lista de objetos "ItemTwitter"
            var results = from tweet in tweets.Descendants("status")
                          select new ItemTwitter
                          {
                              UrlFoto= tweet.Element("user").Element("profile_image_url").Value,
                              Conteudo = tweet.Element("text").Value,
                              Usuario = tweet.Element("user").Element("screen_name").Value
                          };
 
            // -> Alimenta a ListBox.
            lstConteudo.ItemsSource = results.ToList();
        }
    }
}

Percebam que a API do Twitter nada mais é do que uma chamada HTTP que retorna um XML. Faça o teste no seu Navegador.

Após isso, utilizamos o LINQ para criar objetos, a partir do XML, e com eles alimentamos a ListBox, e está pronto nosso leitor de Tweets.

image

É praticamente a mesma coisa fazer essa App em Silverlight, inclusive coloca-la dentro de seu Windows Phone, veja aqui o Scott Gu fazendo isso:
http://weblogs.asp.net/scottgu/archive/2010/03/18/building-a-windows-phone-7-twitter-application-using-silverlight.aspx

Espero que tenham gostado. Alegre

0 comentários: