Silverlight 3: Displaying and Charting with TwitterCounter

A Silverlight application that displays the TwitterCounter user's stats and chart.

I stumbled on to TwitterCounter.com recently and like any typical narcissistic geek, I put my username in there to see their stats on my account. One of the first things I noticed is the nice chart that shows a timeline of your followers counts. Being an ex financial consultant, I love charts. The next thing I noticed is that they have a very easy - to - use API that will return all this data in XML format, which makes is pretty easy to turn into objects that can be bound to Silverlight fields, and the series of chart data can be bound to a Silverlight chart.

So, I set out to have some fun and test my skills with this little Silverlight 3 "TwitterCounter" display app.

When I first checked their API, I saw that there is a crossdomain.xml file present at the root of the site, but for some reason this wasn't working for me, so I resorted to using my ClientAccess.ashx handler to proxy the requests.  In order to have a container for the returned data, I needed a couple of POCO classes:

using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace TwitterCounter
{
    public class TwitterCounter
    {
       public string User_id { get; set; }
        public string User_name { get; set; }
        public string Followers_Current { get; set; }
         public DateTime? Date_updated { get; set; }
         public string Url { get; set; }
        public string Avatar {get; set;}
        public string Follow_since { get; set; }
        public string Started_Followers { get; set; }
         public string Growth_since { get; set; }
        public string Average_growth { get; set; }
        public string Tomorrow { get; set; }
        public string Next_month { get; set; }
        public string Followers_yesterday { get; set; }
         public string Followers2wAgo { get; set; }
        public string GrowthSince2w { get; set; }
        public string AverageGrowth2w { get; set; }
        public string Tomorrow2w { get; set; }
        public string NextMonth2w { get; set; }
        public List<FollowersPerDate> FollowersPerDate { get; set; }


    }

    public class FollowersPerDate
    {
         public DateTime Date { get; set; }
        public int Number { get; set; }
    }
}

Then, I needed a mechanism to download the data by concatenating  the username into the API Url, and process the data:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.DataVisualization.Charting;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml.Linq;

namespace TwitterCounter
{
    public partial class MainPage : UserControl
    {
         public MainPage()
        {
             InitializeComponent();
        }

         private void ButtonSubmit_Click(object sender, RoutedEventArgs e)
        {
            WebClient wc = new WebClient();
             string url = App.TwitterCounterUrl1 + this.txtUserName.Text + App.TwitterCounterUrl2;
            url = App.ConvertUrl(url);
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
             wc.DownloadStringAsync(new Uri(url));
        }

        void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
         {
             if(e.Error!=null)
            {
                MessageBox.Show(e.Error.ToString() );
                 return;
            }
            XElement xel = XElement.Parse(e.Result);
            TwitterCounter tc = new TwitterCounter();
            tc.Avatar = App.AvatarUrl + xel.Element("avatar").Value;
            tc.Average_growth = xel.Element("average_growth").Value;
            tc.User_id = xel.Element("user_id").Value;
            tc.User_name = xel.Element("user_name").Value;
            tc.Followers_Current = xel.Element("followers_current").Value;
            tc.Date_updated = DateTime.Parse(xel.Element("date_updated").Value);
            tc.Url = xel.Element("url").Value;
            tc.Follow_since = xel.Element("follow_since") == null ? "" : xel.Element("follow_since").Value;
            tc.Started_Followers = xel.Element("started_followers").Value;
            tc.Growth_since = xel.Element("growth_since").Value;
            tc.Average_growth = xel.Element("average_growth").Value;
            tc.Tomorrow = xel.Element("tomorrow").Value;
            tc.Next_month = xel.Element("next_month").Value;
            tc.Followers_yesterday = xel.Element("followers_yesterday").Value;
            tc.Followers2wAgo = xel.Element("followers_2w_ago").Value;
            tc.GrowthSince2w = xel.Element("growth_since_2w").Value;
            tc.AverageGrowth2w = xel.Element("average_growth_2w").Value;
            tc.Tomorrow2w = xel.Element("tomorrow_2w").Value;
            tc.NextMonth2w = xel.Element("next_month_2w").Value;
            tc.FollowersPerDate = new List<FollowersPerDate>();

            var perdates = xel.Element("followersperdate").Descendants();
             foreach(var elem in  perdates)
             {
                 tc.FollowersPerDate.Add(new FollowersPerDate()
                      {Date = DateTime.Parse(elem.Name.ToString().Replace("date", "")), Number = Convert.ToInt32(elem.Value)});
             }
             this.LayoutRoot.DataContext = tc;
            LineSeries myLineSeries = LineChart.Series[0] as LineSeries;
             if (myLineSeries != null) { myLineSeries.ItemsSource = getData(tc.FollowersPerDate ); }
         }

         private  KeyValuePair<DateTime, int>[] getData( List<FollowersPerDate> lfpd )      
        {    
            KeyValuePair<DateTime, int>[] dataArray = new KeyValuePair<DateTime, int>[lfpd.Count];
             int i = 0;
             foreach(var followerperdate in lfpd)
            {
                dataArray[i] = new KeyValuePair<DateTime, int>(followerperdate.Date , followerperdate.Number );
                 i++;
            }
            return dataArray;    
         }

        private void Url_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Browser.HtmlPage.Window.Navigate(
                 new Uri(this.Url.Content.ToString()));
        }
    }
}

The result looks like this:



You can download the complete Visual Studio 2008 Silverlight 3 solution here.

By Peter Bromberg   Popularity  (3501 Views)