Since today there is a beta version of a SilverLight livestream control on the homepage of this site, which shows my activity on Twitter, Delicious and this blog. It’s not the most original idea, but it was a small enough project to learn something about SilverLight.
Loading the items
You can use the WebClient class (which internally uses the WebRequest class) to load data from the internet, this has some restrictions. To successfully connect to a site different from the site where the control is hosted, the site has to have a clientaccesspolicy.xml file or a crossdomain.xml which allows remote connections.
For performance reasons all methods on the WebClient class are asynchronous and since I request 3 different streams, I request those using using workitems in the ThreadPool (from a Timerevent every 5 minutes).
public void ProcessFeeds(object state) { // twitter crossdomain.xml is very strict, so we have to have to // use a proxy ThreadPool.QueueUserWorkItem(new WaitCallback(StartLoadFeed), new Uri("http://feeds2.feedburner.com/paulvanbrenk/twitter")); ThreadPool.QueueUserWorkItem(new WaitCallback(StartLoadFeed), new Uri("http://feeds2.feedburner.com/paulvanbrenk/clean")); ThreadPool.QueueUserWorkItem(new WaitCallback(StartLoadFeed), new Uri("http://feeds.delicious.com/v2/rss/paul.van.brenk")); } private void StartLoadFeed(object url) { WebClient client = new WebClient(); client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted); client.OpenReadAsync((Uri)url); } void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { SyndicationFeed feed; using (var xReader = XmlReader.Create(e.Result)) { feed = SyndicationFeed.Load(xReader); } foreach (var item in feed.Items) { Dispatcher.BeginInvoke(new AddItem(delegate(FeedItem x) { feedItems.Add(x); }), FeedItem.Create(item)); } } private delegate void AddItem(FeedItem item);
We need to use the Dispatcher to add the items to the collection, since the collection is bound to a UI element, which responds to changes in the collection.
Binding the items to the UI
The items are bound to the panel which renders them, using the DataContext. This makes it easy to use the Binding Markup Extension to extract information from the bound items and allows the panel to monitor the collection for changes (if the collection implements the INotifyCollectionChanged interface).
Render the items
The items are rendered using an ItemsControl, with the ItemsPanelTemplate set the WrapPanel from the SilverLight Toolkit, this way the items are wrapped over multiple lines. The items are renderd using a DataTemplate in the ItemsTemplate. The image for each type of feed is converted from the type of the item using to an ImageBrush using a class implementing the IValueConverter interface.
Improvements:
[Download the project from http://code.msdn.microsoft.com/LiveStream]