I noticed that Sam over on the Silverlight Show posted about a Windows Phone 7 Series RSS Reader which uses the WebBrowser control to render the content. I figured that whilst that was a neat approach to displaying content an alternative would be to parse the feed, extract the content and display using a combination of TextBlock, Run and LineBreak elements. The following screenshot shows my blog being viewed using such an approach.
Here’s the core code that makes this all happen. It uses the SyndicationFeed class to extract the posts – in my case I’ve just embedded the feed source as a text resource file (hence var rss = RssResources.BlogPosts, where RssResources is a reference to the designer generated wrapper). I then loop through looking for html tags, specifically end of paragraphs and images. I’m sure there’s a more elegant way of doing this but for demo purposes this did the trick.
private void Page_Loaded(object sender, RoutedEventArgs e)
{
// Load RSS into a feed
var rss = RssResources.BlogPosts;
using(var strm = new System.IO.StringReader(rss))
using(var reader = System.Xml.XmlReader.Create(strm))
{
var feed = System.ServiceModel.Syndication.SyndicationFeed.Load(reader);
// Regular expression to look for html tags
var tagFinder = new System.Text.RegularExpressions.Regex("<(.|n)+?>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
// Create the initial textblock
var txt = new TextBlock() { TextWrapping = TextWrapping.Wrap };
this.stackPanel1.Children.Add(txt);
foreach (var item in feed.Items)
{
// Add a title
txt.Inlines.Add(new Run() { FontWeight = FontWeights.Bold, Text = item.Title.Text });
txt.Inlines.Add(new LineBreak());
var itemText = item.Summary.Text;
var match = tagFinder.Match(itemText);
var startidx = 0;
while (match.Index >= 0 && match.Length > 0)
{
if (match.Value == "</p>" || match.Value == "<p />" || match.Value == "<br />")
{
// Found the end of a paragraph, so append this text to the textblock
var text = itemText.Substring(startidx, match.Index – startidx);
text = tagFinder.Replace(text, "");
txt.Inlines.Add(text);
}
else if (match.Value.Contains("<img"))
{
// Add the text up to the image tag
var text = itemText.Substring(startidx, match.Index – startidx);
text = tagFinder.Replace(text, "");
txt.Inlines.Add(text);
// Locate the url of the image
var idx = match.Value.IndexOf("src");
var url = match.Value.Substring(idx + 5, match.Value.IndexOf(""", idx + 6) – (idx + 5));
// Create an image and add to stackpanel
var img = new Image() { Source = new BitmapImage(new Uri(url)) };
img.Width = this.scrollViewer1.ActualWidth / 2;
img.Stretch = Stretch.UniformToFill;
this.stackPanel1.Children.Add(img);
// Create a new textblock and add to stackpanel
txt = new TextBlock() { TextWrapping = TextWrapping.Wrap };
this.stackPanel1.Children.Add(txt);
}
// Look for the next tag
startidx = match.Index + match.Length;
match = tagFinder.Match(itemText, match.Index + 1);
}
// Add the remaining text
txt.Inlines.Add(itemText.Substring(startidx));
// Add some space before the next post
txt.Inlines.Add(new LineBreak());
txt.Inlines.Add(new LineBreak());
}
}
}