logo

Silverlight 3: Displaying and Charting with TwitterCounter

By Peter Bromberg
Printer Friendly Version
View My Articles
379 Views
    

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.

Biography - Peter Bromberg
Peter Bromberg is a C# MVP, MCP, and .NET expert who has worked in banking, financial and telephony for over 20 years. Pete focuses exclusively on the .NET Platform, and currently develops SOA and other .NET applications for a Fortune 500 clientele. Peter enjoys producing digital photo collage with Maya,playing jazz flute, the beach, and fine wines. You can view Peter's UnBlog and IttyUrl sites. Pete Tweets at peterbromberg


Didn't Find The Answer You Were Looking For?

EggHeadCafe has experts online right now that may know the answer to your question.  We pay them a bonus for answering as many questions as they can.  So, why not help them and yourself by becoming a member (free) and ask them your question right now?
Ask Question In Live Forum

If you have an OpenID and do not want to become a member of the EggHeadCafe forum, you can also sign on to Chat Chaos and post your question to our real time Silverlight chat application.
Ask Question In Chat Chaos

Article Discussion: Silverlight 3: Displaying and Charting with TwitterCounter
Peter Bromberg posted at Wednesday, June 17, 2009 10:45 AM
Original Article
 






  $1000 Contest    [)ia6l0 iii - $228  |  Jonathan VH - $161  |  Huggy Bear - $135  |  F Cali - $95  |  egg egg - $94  |  more Advertise  |  Privacy  |   (c) 2010