With the managed WebBrowser control in Windows Forms 2.0, it's a snap to take an RSS feed and display it as formatted HTML text in the browser. Using transformed RSS in lieu of the original site has several benefits: the transformed RSS is usually faster to load; you can manipulate it programmatically with ease to create a standard feel for all syndicated content; and you can easily switch from one blog site to another - perfect if you're building some type of branded RSS reader.

The first thing you need is a way to turn RSS into HTML. I chose to create an XSLT (XSL Transform) document to do the job:

<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="
http://www.w3.org/1999/XSL/Transform" version="1.0"
  xmlns:dc="
http://purl.org/dc/elements/1.1/"
  xmlns:content="
http://purl.org/rss/1.0/modules/content/">
  <xsl:template match="/rss/channel">
    <HTML>
    <HEAD>
      <TITLE>
        <xsl:value-of select="title"/>
      </TITLE>

      <STYLE>
        .PostTitle {
          font-size:16px;
          font-weight:bold;
        }
      </STYLE>
    </HEAD>

    <BODY>

      <DIV class="RssHeader">
        <xsl:for-each select="image">
          <xsl:element name="IMG">
            <xsl:attribute name="src">
              <xsl:value-of select="url"/>
            </xsl:attribute>
            <xsl:attribute name="style">
              float:left;
            </xsl:attribute>
          </xsl:element>
        </xsl:for-each>
        <h2>
          <xsl:element name="a">
            <xsl:attribute name="href">
              <xsl:value-of select="link" />
            </xsl:attribute>
          <xsl:value-of select="title"/>
            </xsl:element>
        </h2>
        <span class="Errata">
          <strong>Description</strong>:
          <xsl:value-of select="description"/>
        </span>
        <br/>
        <span class="Errata">
          <strong>Generated By</strong>:
          <xsl:value-of select="generator"/>
        </span>
        <p/>
        <span class="Errata">
          <xsl:value-of select="copyright"/>
        </span>
      </DIV>
      <HR/>
      <BR/>

      <xsl:for-each select="item">
        <DIV class="PostTitle">
          <xsl:element name="a">
            <xsl:attribute name="href">
              <xsl:value-of select="link" />
            </xsl:attribute>
            <xsl:value-of select="title"/>
          </xsl:element>
        </DIV>
        <DIV class="PostAuthor">
          Author: <xsl:value-of select="dc:creator"/>
        </DIV>
        <DIV class="PostDate">
          Published on <xsl:value-of select="dc:date"/>
        </DIV>
        <DIV class="PostContent">
          <xsl:value-of select="description" disable-output-escaping="yes"/>
        </DIV>
        <BR/>
        <HR/>
        <BR/>
      </xsl:for-each>

    </BODY>
  </HTML>
</xsl:template>
</xsl:stylesheet>

Now, however, we need a way to execute the transform in code. Not a problem: Just use the XslCompiledTransform class defined in System.Xml.Xsl to pull this off. (NOTE: I do all exception handling in the caller of this method.)

        private StringBuilder TransformFeed(Uri feedUri, string xsltPath)
        {
            StringBuilder writtenHtmlString = new StringBuilder();
            XmlWriter writtenHtml = null;
            XmlDocument xmlDoc = new XmlDocument();

            xmlDoc.Load(feedUri.ToString());
               
            writtenHtml = XmlWriter.Create(writtenHtmlString);

            // Perform a transform. 
            XslCompiledTransform xslt = new XslCompiledTransform();
            xslt.Load(xsltPath);
            xslt.Transform(xmlDoc, writtenHtml);
            writtenHtml.Close();

            return (writtenHtmlString);
        }

Assign this HTML to the DocumentText property of the WebBrowser control on your form, and you're golden. Add a TreeView to your app to maintain a list of categorized blog feed, throw in a persistence mechanism for the user's list of blogs to watch (say, perhaps, Application Settings?), and you have yourself a basic RSS feed reader in Windows Forms.