Building a Twitter Search Client using WPF under C#
The client is very simple.
It’s basically a TextBlock (txtSearch), one Button (btnSearch) and a ListBox (lstTweets). Note that you should save the twitter logo provided in this post (twitter_3_512.png), and add it to the root of the solution.
Using WPF I jazzed it up making each ListItem look like a speech bubble, a gradient background, a nice looking image and user icons from Twitter.
So to make the client I created a TwitterSearch class that does all the dirty work:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Xml.Linq;
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
namespace TweetSearch
{
public class Tweet
{
public string Id { get; set; }
public DateTime Published { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public string Link { get; set; }
public Author Author { get; set; }
public string Image { get; set; }
}
public class Author
{
public string Name { get; set; }
public string Uri { get; set; }
}
public class TwitterSearch
{
public static List<Tweet> GetSearchResults(string searchString)
{
using (WebClient web = new WebClient())
{
string url = string.Format("http://search.twitter.com/search.atom?lang=en&q={0}", searchString);
WebClient client = new WebClient();
XDocument doc = XDocument.Load(url);
XNamespace ns = "http://www.w3.org/2005/Atom";
List<Tweet> tweets = (from item in doc.Descendants(ns + "entry")
select new Tweet
{
Id = item.Element(ns + "id").Value,
Published = DateTime.Parse(item.Element(ns + "published").Value),
Title = item.Element(ns + "title").Value,
Content = item.Element(ns + "content").Value,
Link = (from XElement x in item.Descendants(ns + "link")
where x.Attribute("type").Value == "text/html"
select x.Attribute("href").Value).First(),
Image = (from XElement x in item.Descendants(ns + "link")
where x.Attribute("type").Value == "image/png"
select x.Attribute("href").Value).First(),
Author = new Author()
{
Name = item.Element(ns + "author").Element(ns + "name").Value,
Uri = item.Element(ns + "author").Element(ns + "uri").Value
}
}).ToList();
return tweets;
}
}
}
}
The only thing left to do is make the pretty UI. Here is the c# code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace TweetSearch
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private void btnSearch_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(txtSearch.Text)) return;
try
{
Cursor = Cursors.Wait;
List<Tweet> searchResults = TwitterSearch.GetSearchResults(txtSearch.Text);
lstTweets.ItemsSource = searchResults;
}
finally
{
Cursor = Cursors.Arrow;
}
}
private void lstTweets_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (lstTweets.SelectedItem == null) return;
Tweet tweet = (Tweet)lstTweets.SelectedItem;
//Process.Start(tweet.Link);
}
}
}
And of course the XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="TweetSearch.MainWindow"
Title="TweetSearch" Height="755" Width="961" Icon="twitter_3_512.png" WindowState="Maximized">
<Window.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF17B6EB" Offset="0"/>
<GradientStop Color="#FFA7E4FF" Offset="1"/>
</LinearGradientBrush>
</Window.Background>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="324.135"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image Margin="8,0,0,144" Source="twitter_3_512.png" Stretch="Fill" Height="311" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="311.135"/>
<TextBox x:Name="txtSearch" Height="26" Margin="49,0,43,118" TextWrapping="Wrap" VerticalAlignment="Bottom"/>
<ListBox x:Name="lstTweets" Grid.Column="1" Margin="8,8,8,0" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White" ScrollViewer.HorizontalScrollBarVisibility="Disabled" SelectionChanged="lstTweets_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid VerticalAlignment="Top" Cursor="Hand" Margin="5,5,5,5">
<Grid.Effect>
<DropShadowEffect BlurRadius="13" ShadowDepth="1" Color="#FF578EA4"/>
</Grid.Effect>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="14"/>
</Grid.RowDefinitions>
<Rectangle Fill="White" Stroke="#FF2CBBF0" RadiusX="10" RadiusY="10"/>
<Path Fill="White" Stretch="Fill" Stroke="#FF2CBBF0" HorizontalAlignment="Left" Margin="30,-5.597,0,0" Width="25" Grid.Row="1" Data="M22.166642,154.45381 L29.999666,187.66699 40.791059,154.54395" Height="19.6" VerticalAlignment="Top" RenderTransformOrigin="-0.685,0.49"/>
<Rectangle Fill="White" RadiusX="10" RadiusY="10" Margin="1"/>
<DockPanel Margin="5,5,5,5">
<Image Source="{Binding Image}" Height="50" Width="50" DockPanel.Dock="Left" />
<StackPanel Margin="5,0,0,0" >
<TextBlock FontSize="13" Text="{Binding Author.Name}" FontWeight="Bold" Foreground="Black" />
<TextBlock FontSize="13" Text="{Binding Title}" Foreground="Black" />
</StackPanel>
</DockPanel>
<Grid.Triggers>
<EventTrigger RoutedEvent="Control.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="1" Duration="0:0:0.5" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
</WrapPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<Button x:Name="btnSearch" Content="Search" Height="25" Margin="122,0,126.135,89" VerticalAlignment="Bottom" Click="btnSearch_Click" IsDefault="True" />
</Grid>
</Window>
Try it yourself, and contact me for any question or issues.
It’s basically a TextBlock (txtSearch), one Button (btnSearch) and a ListBox (lstTweets). Note that you should save the twitter logo provided in this post (twitter_3_512.png), and add it to the root of the solution.
Using WPF I jazzed it up making each ListItem look like a speech bubble, a gradient background, a nice looking image and user icons from Twitter.
So to make the client I created a TwitterSearch class that does all the dirty work:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Xml.Linq;
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
namespace TweetSearch
{
public class Tweet
{
public string Id { get; set; }
public DateTime Published { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public string Link { get; set; }
public Author Author { get; set; }
public string Image { get; set; }
}
public class Author
{
public string Name { get; set; }
public string Uri { get; set; }
}
public class TwitterSearch
{
public static List<Tweet> GetSearchResults(string searchString)
{
using (WebClient web = new WebClient())
{
string url = string.Format("http://search.twitter.com/search.atom?lang=en&q={0}", searchString);
WebClient client = new WebClient();
XDocument doc = XDocument.Load(url);
XNamespace ns = "http://www.w3.org/2005/Atom";
List<Tweet> tweets = (from item in doc.Descendants(ns + "entry")
select new Tweet
{
Id = item.Element(ns + "id").Value,
Published = DateTime.Parse(item.Element(ns + "published").Value),
Title = item.Element(ns + "title").Value,
Content = item.Element(ns + "content").Value,
Link = (from XElement x in item.Descendants(ns + "link")
where x.Attribute("type").Value == "text/html"
select x.Attribute("href").Value).First(),
Image = (from XElement x in item.Descendants(ns + "link")
where x.Attribute("type").Value == "image/png"
select x.Attribute("href").Value).First(),
Author = new Author()
{
Name = item.Element(ns + "author").Element(ns + "name").Value,
Uri = item.Element(ns + "author").Element(ns + "uri").Value
}
}).ToList();
return tweets;
}
}
}
}
The only thing left to do is make the pretty UI. Here is the c# code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace TweetSearch
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private void btnSearch_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(txtSearch.Text)) return;
try
{
Cursor = Cursors.Wait;
List<Tweet> searchResults = TwitterSearch.GetSearchResults(txtSearch.Text);
lstTweets.ItemsSource = searchResults;
}
finally
{
Cursor = Cursors.Arrow;
}
}
private void lstTweets_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (lstTweets.SelectedItem == null) return;
Tweet tweet = (Tweet)lstTweets.SelectedItem;
//Process.Start(tweet.Link);
}
}
}
And of course the XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="TweetSearch.MainWindow"
Title="TweetSearch" Height="755" Width="961" Icon="twitter_3_512.png" WindowState="Maximized">
<Window.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF17B6EB" Offset="0"/>
<GradientStop Color="#FFA7E4FF" Offset="1"/>
</LinearGradientBrush>
</Window.Background>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="324.135"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image Margin="8,0,0,144" Source="twitter_3_512.png" Stretch="Fill" Height="311" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="311.135"/>
<TextBox x:Name="txtSearch" Height="26" Margin="49,0,43,118" TextWrapping="Wrap" VerticalAlignment="Bottom"/>
<ListBox x:Name="lstTweets" Grid.Column="1" Margin="8,8,8,0" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White" ScrollViewer.HorizontalScrollBarVisibility="Disabled" SelectionChanged="lstTweets_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid VerticalAlignment="Top" Cursor="Hand" Margin="5,5,5,5">
<Grid.Effect>
<DropShadowEffect BlurRadius="13" ShadowDepth="1" Color="#FF578EA4"/>
</Grid.Effect>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="14"/>
</Grid.RowDefinitions>
<Rectangle Fill="White" Stroke="#FF2CBBF0" RadiusX="10" RadiusY="10"/>
<Path Fill="White" Stretch="Fill" Stroke="#FF2CBBF0" HorizontalAlignment="Left" Margin="30,-5.597,0,0" Width="25" Grid.Row="1" Data="M22.166642,154.45381 L29.999666,187.66699 40.791059,154.54395" Height="19.6" VerticalAlignment="Top" RenderTransformOrigin="-0.685,0.49"/>
<Rectangle Fill="White" RadiusX="10" RadiusY="10" Margin="1"/>
<DockPanel Margin="5,5,5,5">
<Image Source="{Binding Image}" Height="50" Width="50" DockPanel.Dock="Left" />
<StackPanel Margin="5,0,0,0" >
<TextBlock FontSize="13" Text="{Binding Author.Name}" FontWeight="Bold" Foreground="Black" />
<TextBlock FontSize="13" Text="{Binding Title}" Foreground="Black" />
</StackPanel>
</DockPanel>
<Grid.Triggers>
<EventTrigger RoutedEvent="Control.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="1" Duration="0:0:0.5" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
</WrapPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<Button x:Name="btnSearch" Content="Search" Height="25" Margin="122,0,126.135,89" VerticalAlignment="Bottom" Click="btnSearch_Click" IsDefault="True" />
</Grid>
</Window>
Try it yourself, and contact me for any question or issues.
0 Response to "Building a Twitter Search Client using WPF under C#"
Post a Comment