Twitter + Silverlight ou WPF
Autor: Eduardo Spaki | Publicado: 2011-11-15T18:31:00-02:00

Vamos fazer um cliente de Twitter???  Vamos!   Ebaaa...     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:    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:          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:         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:     &lt;Window x:Class=&quot;MeuClienteDeTwitter.MainWindow&quot;       &#160;&#160;&#160;&#160;&#160;&#160;&#160; xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;      &#160;&#160;&#160;&#160;&#160;&#160;&#160; xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;      &#160;&#160;&#160;&#160;&#160;&#160;&#160; Title=&quot;MainWindow&quot; Height=&quot;484&quot; Width=&quot;385&quot;&gt;       &#160;&#160;&#160; &lt;!--Definindo o fundo em gradiente da janela--&gt;        &#160;&#160;&#160; &lt;Window.Background&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;LinearGradientBrush EndPoint=&quot;1,0.5&quot; StartPoint=&quot;0,0.5&quot;&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;GradientStop Color=&quot;LightBlue&quot; Offset=&quot;0&quot; /&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;GradientStop Color=&quot;White&quot; Offset=&quot;1&quot; /&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/LinearGradientBrush&gt;        &#160;&#160;&#160; &lt;/Window.Background&gt;        &#160;&#160;&#160; &lt;Grid&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!--Definindo as linhas da grid para o layout.         &#160;&#160;&#160;&#160;&#160;&#160;&#160; O &quot;*&quot; representa o tamanho que sobrar da jenala,        &#160;&#160;&#160;&#160;&#160;&#160;&#160; após utilizar os 80 da linha de cima--&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;Grid.RowDefinitions&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;RowDefinition Height=&quot;80&quot; /&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;RowDefinition Height=&quot;*&quot; /&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/Grid.RowDefinitions&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;Label Content=&quot;Meu Cliente de Twitter&quot; Height=&quot;28&quot; HorizontalAlignment=&quot;Left&quot; Margin=&quot;12,12,0,0&quot; Name=&quot;label1&quot; VerticalAlignment=&quot;Top&quot; FontWeight=&quot;Bold&quot; FontSize=&quot;16&quot; FontFamily=&quot;Verdana&quot; /&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;TextBox Height=&quot;23&quot; HorizontalAlignment=&quot;Left&quot; Margin=&quot;12,46,0,0&quot; Name=&quot;txtUsuario&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;213&quot; /&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;Button Content=&quot;Carregar o Twitter&quot; Height=&quot;23&quot; HorizontalAlignment=&quot;Left&quot; Margin=&quot;231,46,0,0&quot; Name=&quot;btnCarregar&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;124&quot; Click=&quot;btnCarregar_Click&quot; /&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;ListBox Grid.Row=&quot;1&quot; Name=&quot;lstConteudo&quot; BorderBrush=&quot;{x:Null}&quot; Background=&quot;{x:Null}&quot;&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!--Template que define o layout de cada item da ListBox--&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;ListBox.ItemTemplate&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;DataTemplate&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!--Perceba que foi utilizado um outro painel para definir o layout--&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;StackPanel Orientation=&quot;Horizontal&quot; Height=&quot;132&quot;&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;Image Source=&quot;{Binding UrlFoto}&quot; Height=&quot;73&quot; Width=&quot;73&quot; VerticalAlignment=&quot;Top&quot; Margin=&quot;0,10,8,0&quot; /&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;StackPanel Width=&quot;370&quot;&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;TextBlock Text=&quot;{Binding Usuario}&quot; Foreground=&quot;#FFC8AB14&quot; FontSize=&quot;28&quot;/&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;TextBlock Text=&quot;{Binding Conteudo}&quot; TextWrapping=&quot;Wrap&quot; FontSize=&quot;23&quot;/&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/StackPanel&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/StackPanel&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/DataTemplate&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/ListBox.ItemTemplate&gt;        &#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/ListBox&gt;        &#160;&#160;&#160; &lt;/Grid&gt;        &lt;/Window&gt;   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=&quot;Wrap&quot;”).  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”.    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 &gt; Add &gt; Class. Veja na imagem abaixo:    O nome dela será “ItemTwitter”, o código fonte está abaixo:     namespace MeuClienteDeTwitter       {        &#160;&#160;&#160; public class ItemTwitter        &#160;&#160;&#160; {        &#160;&#160;&#160;&#160;&#160;&#160;&#160; public string UrlFoto { get; set; }        &#160;&#160;&#160;&#160;&#160;&#160;&#160; public string Usuario { get; set; }        &#160;&#160;&#160;&#160;&#160;&#160;&#160; public string Conteudo { get; set; }        &#160;&#160;&#160; }        }   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;        &#160; namespace MeuClienteDeTwitter        {        &#160;&#160;&#160; public partial class MainWindow : Window        &#160;&#160;&#160; {        &#160;&#160;&#160;&#160;&#160;&#160;&#160; public MainWindow()        &#160;&#160;&#160;&#160;&#160;&#160;&#160; {        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; InitializeComponent();        &#160;&#160;&#160;&#160;&#160;&#160;&#160; }        &#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160; // -&gt; Método do evento de click do botão para carregar os tweets.        &#160;&#160;&#160;&#160;&#160;&#160;&#160; private void btnCarregar_Click(object sender, RoutedEventArgs e)        &#160;&#160;&#160;&#160;&#160;&#160;&#160; {        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // -&gt; Criamos um objeto que fará uma requisição web para a API do Twitter.        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; var requisicao = new WebClient();        &#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // -&gt; Concatenando o nome do usuário digitado na txtUsuario na URL da API do Twitter.        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; var url = string.Format(&quot;http://api.twitter.com/1/statuses/user_timeline.xml?screen_name={0}&quot;, txtUsuario.Text);       &#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; /*        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; -&gt; Faremos a requisição web de forma assincrona, ou seja,        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; * a requisição é disparada a aplicação não ficará travada até ela responder.        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; * Mas quando ela responder, deve responder para a aplicação com um evento.        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; * Então temos que definir o evento que ela responderá &quot;requisicao_DownloadStringCompleted&quot;.        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; * Agora podemos fazer a requisição assincrona, passando a URL da API, atravéz da classe URI.        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; */        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; requisicao.DownloadStringCompleted += new DownloadStringCompletedEventHandler(requisicao_DownloadStringCompleted);        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; requisicao.DownloadStringAsync(new Uri(url));        &#160;&#160;&#160;&#160;&#160;&#160;&#160; }        &#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160; void requisicao_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)        &#160;&#160;&#160;&#160;&#160;&#160;&#160; {        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // -&gt; Todo o retorno do prossessamento da requisição virá na variável &quot;e&quot;.        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // -&gt; Verificamos se houve algum erro.        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (e.Error != null)        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return;        &#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // -&gt; o Retorno da requisição é um XML. Teste no seu navegador para averiguar.        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; //&#160;&#160;&#160;&#160;&#160; Então fazemos um parse nele para utilizar o LINQ.        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; var tweets = XElement.Parse(e.Result);        &#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // -&gt; Usando o LINQ, tranformamos os nós do XML em uma lista de objetos &quot;ItemTwitter&quot;        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; var results = from tweet in tweets.Descendants(&quot;status&quot;)        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; select new ItemTwitter        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; UrlFoto= tweet.Element(&quot;user&quot;).Element(&quot;profile_image_url&quot;).Value,        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Conteudo = tweet.Element(&quot;text&quot;).Value,        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Usuario = tweet.Element(&quot;user&quot;).Element(&quot;screen_name&quot;).Value        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; };        &#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; // -&gt; Alimenta a ListBox.        &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; lstConteudo.ItemsSource = results.ToList();        &#160;&#160;&#160;&#160;&#160;&#160;&#160; }        &#160;&#160;&#160; }        }   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.    É 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.