How to Data Bind to an RSS Feed (Blog Posts) in Windows Forms

RSS feeds are XML files that represent the current posts on a
syndicated content channel, such as a blog or news feed. Since RSS
feeds are XML, they can be loaded into an ADO.NET DataSet and bound to
the elements of a form.

Picture 1: Simple RSS Feed Reader

The following C# code shows the basics of wiring up a feed to a form so
that the title element is bound to a Label and the description (blog
post content) is bound to the DocumentText property of the WebBrowser
control. The method GetBlogPost() is called in my code from a list of entries contained on a ToolStrip control; I use the Padding property of ToolStripItem to make the ToolStrip list appear as a categorized hierarchy of max one depth level. The feed URI is saved in the Tag property of the ToolStripButton, which is what the user clicks to call GetBlogPost(). The button controls at the bottom of the form allow you to flip back and forward through the currently available posts in the latest version of the feed.

The form for this sample requires these controls:

postTitleLink: LinkLabel
webBrowser1: WebBrowser
firstbutton, lastButton, previousButton, nextButton: Button

The trickiest part of this code occurs partway down the GetBlogPosts() method, where I need to obtain the list of item elements in the RSS feed to which I data bind. The item elements are consider children of the channel element. When I load the XML file into an ADO.NET DataSet, ADO.NET makes the item elements available as a DataRelation whose name is a conjunction of the channel and item elements. In other words, to get at the item elements, I have to use this line:

           bindingTable = dt.ChildRelations["channel_item"].ChildTable;

- where dt is the name of my DataTable containing the RSS data.

Here's the full sample. (NOTE: This is a preview of a full sample I'll be publishing as the subject of a white paper in July. The final sample will be more fleshed out than this skeleton sample.)

        private void GetBlogPost(string feed)
{
DataSet ds = new DataSet();
XmlReader reader = null;

try
{
reader = XmlReader.Create(feed);
}
catch (FileNotFoundException fileEx)
{
MessageBox.Show("Cannot file blog feed. Error returned: " + fileEx.Message);
return;
}
catch (SecurityException secEx)
{
MessageBox.Show("You do not have permission to view this feed. Error returned: " + secEx.Message);
return;
}

// Cruise forward to the <item> elements.
reader.ReadToDescendant("channel");

ds.ReadXml(reader);
DataTable dt = ds.Tables[0];

// Set up data binding.
bindingTable = dt.ChildRelations["channel_item"].ChildTable;
postTitleLink.DataBindings.Add(new Binding("Text", bindingTable, "title"));
//dateLabel.DataBindings.Add(new Binding("Text", bindingTable, "dc:date"));
webBrowser1.DataBindings.Add(new Binding("DocumentText", bindingTable, "description"));

// Set the Previous and Next buttons as applicable.
previousButton.Enabled = false;
BindingManagerBase myContext = this.BindingContext[bindingTable];
if (myContext.Count == 1)
{
nextButton.Enabled = false;
lastButton.Enabled = false;
}
else
{
nextButton.Enabled = true;
lastButton.Enabled = true;
}

firstButton.Enabled = false;

recordLabel.Text = (myContext.Position + 1).ToString();

myContext.CurrentChanged += new EventHandler(myContext_CurrentChanged);
}

void myContext_CurrentChanged(object sender, EventArgs e)
{
recordLabel.Text = (this.BindingContext[bindingTable].Position + 1).ToString();
}

private void nextButton_Click(object sender, EventArgs e)
{
BindingManagerBase myContext = this.BindingContext[bindingTable];
myContext.Position += 1;
previousButton.Enabled = true;
if (myContext.Position + 1 == myContext.Count)
{
nextButton.Enabled = false;
lastButton.Enabled = false;
}
if (myContext.Position == 1)
{
firstButton.Enabled = true;
}
}

private void previousButton_Click(object sender, EventArgs e)
{
BindingManagerBase myContext = this.BindingContext[bindingTable];
myContext.Position -= 1;
nextButton.Enabled = true;
if (myContext.Position == 0)
{
previousButton.Enabled = false;
firstButton.Enabled = false;
}
if (myContext.Position + 2 == myContext.Count)
{
lastButton.Enabled = true;
}
}

private void firstButton_Click(object sender, EventArgs e)
{
BindingManagerBase myContext = this.BindingContext[bindingTable];
myContext.Position = 0;
previousButton.Enabled = false;
firstButton.Enabled = false;
if (lastButton.Enabled == false)
{
lastButton.Enabled = true;
nextButton.Enabled = true;
}
}

private void lastButton_Click(object sender, EventArgs e)
{
BindingManagerBase myContext = this.BindingContext[bindingTable];
myContext.Position = myContext.Count - 1;
nextButton.Enabled = false;
lastButton.Enabled = false;
if (firstButton.Enabled == false)
{
firstButton.Enabled = true;
previousButton.Enabled = true;
}
}

private void postTitleLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
BindingManagerBase myContext = this.BindingContext[bindingTable];
DataRowView rowView = (DataRowView)myContext.Current;
string permalink = rowView["link"].ToString();
Process.Start(permalink);
}