65.9K
CodeProject 正在变化。 阅读更多。
Home

RSS新闻阅读器

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.58/5 (8投票s)

2005年5月9日

11分钟阅读

viewsIcon

120954

downloadIcon

3673

一个 VB.NET RSS 新闻阅读器。RSS 站点存储在 Access 数据库中,项目可以从 DataGrid 中选择。选定的新闻项目显示在嵌入式浏览器中。

Sample Image

引言

这是一个简单的 RSS 新闻阅读器。RSS 订阅源站点列表包含在 Access 数据库中。新闻站点显示在 DataGrid 中,用户可以选择感兴趣的新闻站点。在此步骤之后,用户可以获取选定 RSS 新闻订阅源站点中的所有新闻项目。这些项目显示在另一个 DataGrid 中。用户根据项目标题和/或描述选择感兴趣的新闻项目。选定的新闻项目显示在浏览器中,并可以在选定的新闻项目中进行向前和向后扫描。

背景

如果用户对 Access 数据库和 VB.NET 接口有所了解,将会有帮助

使用代码

此程序可以自定义,以添加搜索功能,使用户能够根据标题、描述或类别选择新闻项目。DataSetReadXML 方法用于从站点读取 XML 数据。这适用于符合 RSS 2.0 标准的站点。数据库是 Access,可以升级。请注意,在源代码中,数据库文件 rss.mdb 包含在源代码文件夹中。编译时,请确保先将其放入 bin 文件夹,然后编译代码。代码旨在在 bin 文件夹中查找数据库文件。如果在 bin 文件夹中找不到,它将显示错误。

帮助配置自我的网站,我已经设置了该网站以协助用户查询。我计划随着时间的推移向该网站添加材料。该代码展示了简单的 VB.NET 编码,我用它来演示数据库连接、SQL 查询、DataGrid 自定义、菜单、应用程序数据和 XML 数据管理。

该程序使用 OLEDB 数据适配器连接到 Access 数据库。Access 数据库文件 rss.mdb 包含两个表,rssSitesItemsrssSites 表保存 RSS 新闻站点列表和站点描述。此表中的 XMLURL 字段包含站点地址。SiteNameDescription 字段包含新闻站点的名称以及该站点提供的新闻类型的描述。我添加了 72 个站点,用户可以添加任何其他感兴趣的站点并编辑此数据。目前,您需要 MS Access 才能打开和编辑此文件。我计划在 RSS 新闻阅读器中添加一个编辑页面,以允许用户从程序的 GUI 管理此表。Items 表旨在保存用户选择的新闻站点中的新闻项目信息。此表可能会随着时间增长,我已经编写了代码来帮助用户维护此表。用户需要注意,新闻订阅源不会永远在线,旧的新闻项目 URL 几天后将无法连接。我没有为该表添加日期字段。RSS 数据包含作者和发布日期信息。用户可以轻松修改程序以添加这些功能。每个表都有一个名为 ViewBoolean 字段,当用户选择新闻站点或新闻项目时,该字段设置为 True。有一个查询 ViewItems,它从 Items 表中筛选出 View 设置为 True 的记录;这些是用户选择的项目。rssSitesItems 表之间存在一对多关系。

我使用 OLEDB 连接向导来简化连接到数据库的任务。当然,如果您有这方面的经验,可以编写更高效的代码来连接到数据库。有三个 OLEDB 数据适配器,OleDbdaSites 用于获取 rssSites 表,OldDbdaItems 用于获取 Items 表,以及 OleDbdaViewItems 用于从数据库获取 ViewItems 查询。

DataGrid 的表格样式

让我们从第一步开始,即 GUI。有两个 DataGrid 用于显示来自两个表的数据。DataGridAllowSorting 属性设置为 True。这允许用户单击 DataGrid 中的列标题并按字母顺序对数据进行排序。最后,TableStyles 属性用于自定义 DataGrid 列。我使用设计器中的属性窗口来自定义列。打开表格样式的集合编辑器,然后进入网格列样式集合。添加一个布尔列和两个文本框列。列样式属性的映射名称属性设置为字段值。将布尔列设置为显示 View 列(布尔项),并使用两个文本列显示站点名称和站点描述。将布尔列的 AllowNull 属性设置为 False。默认值为一个三值复选框,包含 TrueNullFalse。将此属性设置为 False 会使复选框仅变为 TrueFalseReadOnly 属性决定用户是否可以编辑列的值。对于 View 列(因为必须允许用户选择他们想要访问的站点或想要查看的项目),此属性设置为 False,对于其他列也设置为 False,以防止用户编辑这些值。

添加了一个菜单以简化 GUI 导航。菜单项 mnuGetFeeds 的代码调用 GetNewsFeeds 过程,该过程从 DataGrid dgdSites 中选定(View = True)的站点获取新闻项目列表。代码仅在缓存的 DataSetrssSites 表中有项目时运行。创建一个 DataRow 对象来保存每一行,代码遍历 DataSetView 设置为 True 的行。

Dim dr As DataRow

新闻站点的 URL(rssSites 表中 XMLURL 字段的值)和 ID 号被传递给 GetNewsFeedItemsFromSite 过程。

strUrl = dr.Item("XMLURL").ToString
intSiteID = Val(dr.Item("id").ToString)
' call procedure to read URL and get RSS Item feed
GetNewsFeedItemsFromSite(strUrl, intSiteID)
Private Sub GetNewsFeeds()
    ' Update database to make sure sites selected are stored in database
    Me.OleDbdaSites.Update(Me.DataSet11.rsssites)
    Dim i As Integer, j As Integer
    i = Me.DataSet11.rsssites.Rows.Count
    If i >= 1 Then
        ' Loop from first (index 0) to i-1th (last) item in the rss sites table
        For j = 0 To i - 1
            Dim dr As DataRow
            Dim strUrl As String, intSiteID As Integer
            dr = Me.DataSet11.rsssites.Rows(j)
            ' select only sites with view checkbox selected by user.
            If dr.Item("View") = True Then
                strUrl = dr.Item("XMLURL").ToString
                intSiteID = Val(dr.Item("id").ToString)
                ' call procedure to read URL and get RSS Item feed
                GetNewsFeedItemsFromSite(strUrl, intSiteID)
            End If
        Next
    End If
    ' Refresh the item dataset with the updated data from the item table
    Me.OleDbdaItem.Fill(Me.DataSet11.item)
    ' Display the items dataset in the datagrid
    Me.dgdItems.Refresh()
End Sub

GetNewsFeedItemsFormSite 过程创建一个新的 DataSet,并使用 DataSetReadXML 方法读取和解析站点中的 XML 数据。

Dim ds As New DataSet
On Error GoTo errsub
ds.ReadXml(strUrl)

如果站点的 XML 因错误而无法解析,则 OnError 语句会捕获错误并显示错误消息。RSS 订阅源是 XML 数据,它被读取到 DataSet 中的表中。表名是 rsschannelimageitemguidrss 表有一个名为 version 的列;对于 RSS 2.0,其值为 2.0。channel 表有名为 titlelinkdescriptioncopyrightlanguagelastBuildDate 的列。这是频道的描述。请注意,en-us 是语言的美国英语。image 表有名为 urltitlelink 的列。item 表有名为 titlelinkdescriptionauthorpubDate 的列,用于频道中的每个项目。guid 表有名为 isPermaLinkguid_Text 的列。

strUrl = ds.Tables("Item").Rows(intRow).Item("link").ToString

新闻项目的 URL(RSS 订阅源中的每个新闻项目都有其唯一的 URL)从传递到数据集表 Item 的 XML 数据中读取。

Access 在包含撇号的 SQL 语句中存在问题,Replace 语句将每个撇号替换为双撇号以避免错误。如果您在 MS SQL Server 中使用存储过程,则可以使用参数传递数据,并避免此代码。此外,Access 将文本字段限制为 255 个字符,我编写了代码来限制字符串长度。

strItemURL = SQLString(strItemURL, 250)

执行此任务的函数 SQLString 将在后面的注释中显示。

创建了一个新命令来将数据插入到 Items 表中。如果您选择也存储 AuthorpubDate 信息,则需要将列添加到 Access 数据库中,读取并清理数据,然后修改 Insert 命令。请注意在代码中使用下划线来包装长字符串并使其可读。下划线之前必须有一个空格。

MyCommand.CommandText = _
    "Insert into Item (title,link,description,siteid) VALUES " & _
    "('" & strTitle & "','" & strUrl & "','" & _
    strDescription & "'," & intSiteID & ")"

这里使用了数据适配器向导之前创建的连接。

If Me.OleDbConnection1.State <> ConnectionState.Open Then
  Me.OleDbConnection1.Open()
End If                          
MyCommand.Connection = Me.OleDbConnection1

确保连接已打开,如果已关闭则将其打开。该命令在 For-Next 循环的下一个周期中重复,并且必须在重新创建命令之前删除它。

MyCommand.Dispose()
Private Sub GetNewsFeedItemsFromSite(ByVal _
                 strURL As String, ByVal intSiteID As Integer)
    Dim intRowsAffected As Integer
    On Error GoTo errsub
    Dim ds As New DataSet
    ds.ReadXml(strURL)
    Dim intCount As Integer, intRow As Integer
    Dim strTitle As String, strDescription As String
    Dim strItemURL As String
    ' get number of rows in item table from XML page dataset
    intCount = ds.Tables("Item").Rows.Count
    ' you have data to add to the item table
    ' in the database only if there is at least one row
    If intCount > 0 Then
        ' loop through rows in the item table in the XML page dataset
        For intRow = 0 To intCount - 1
            'Get values from dataset
            ' Replace apostrophe with double
            ' apostrophe for Access text fields
            ' Limit string length for Access database
            ' text field. This can be longer if
            ' you use Oracle, DB2, or SQL Server
            strItemURL = ds.Tables("Item").Rows(intRow).Item("link").ToString
            strItemURL = SQLString(strItemURL, 250)

            strTitle = ds.Tables("Item").Rows(intRow).Item("title").ToString
            strTitle = SQLString(strTitle, 100)

            strDescription = _
              ds.Tables("Item").Rows(intRow).Item("description").ToString
            strDescription = SQLString(strDescription, 250)

            Dim MyCommand As New OleDb.OleDbCommand
            ' Insert news feed items from selected RSS sites into items table
            ' Other fields like author
            ' and data of publication can also be added here
            MyCommand.CommandText = _
                "Insert into Item (title,link,description,siteid) VALUES " & _
                "('" & strTitle & "','" & strItemURL & _
                "','" & strDescription & "'," & intSiteID & ")"
            If Me.OleDbConnection1.State <> ConnectionState.Open Then
                Me.OleDbConnection1.Open()
            End If
            MyCommand.Connection = Me.OleDbConnection1
            intRowsAffected = MyCommand.ExecuteNonQuery()
            MyCommand.Dispose()
            '  MsgBox("insert done" & intRowsAffected.ToString & _
            '              " rows", MsgBoxStyle.Information, "Message")
        Next
        '   MsgBox("done with items", MsgBoxStyle.Information, "Message")
    Else
        MsgBox("No sites selected; No news items", _
                        MsgBoxStyle.Information, "Message")
    End If
    Exit Sub
errsub:
    MsgBox(Err.Description, MsgBoxStyle.Critical, "Error")
End Sub

Replace 命令用于将字段值中的单个撇号替换为双撇号。如果单个撇号传递给 SQL,Access 会将其视为 SQL 语句的结尾。

strSQL = Replace(strSQL, "'", "''")

请注意,这是逗号前用双引号括起来的撇号,以及逗号后用双引号括起来的两个撇号。

Private Function SQLString(ByVal strSQL As String, _
                ByVal intLength As Integer) As String
    strSQL = Replace(strSQL, "'", "''")
    If strSQL.Length > intLength Then
        strSQL = strSQL.Substring(0, intLength)
    End If
    Return strSQL
End Function

在用选定站点的新闻项目填充 Items 表后,用户选择他/她想要查看的项目。我设置的方式是,系统会记住以前添加到数据库中的所有新闻项目,并且需要对列表进行筛选,以防止它变得过大。我在“新闻项目”菜单下有代码,用于删除未选定的项目,或删除所有项目。由于旧的新闻源 URL 不由新闻站点维护,因此保留非常旧的链接是不划算的。您可以修改代码以根据发布日期自动删除旧项目。

“新闻项目”下的“获取选定新闻项目”菜单项包含代码,可转到新闻站点并拉出项目并在浏览器窗口中显示它。我使用了 VS.NET 附带的 AxWebBrowser 控件。通过“项目”、“添加引用”、“COM 项目”将浏览器控件添加到项目中,然后选择并添加 Microsoft Internet Controls。我自己使用 FireFox 浏览器,并计划在未来的版本中使用它。

Me.OleDbdaViewItems.Fill(Me.DataSet11.ViewItems)
intItemstoView = Me.DataSet11.ViewItems.Rows.Count

DataSet 中的 ViewItems 表包含数据库中 ViewiITems 查询的输出。这会选择查看者选择的新闻项目。查看者选择的项目数量存储在窗体级变量 intItemstoView 中。

GetFeed 过程将浏览器导航到选定站点的 URL。请注意,参数指的是项目的索引号。

GetFeed(intItemViewed)

同样,使用 DataRow 对象获取每一行中的值,并将链接(超链接)列中的值存储在字符串变量 strURL 中。这是单个新闻项目的 URL,而不是整个站点的 URL。Web 浏览器对象被设置为导航到该站点。站点的 URL 显示在输出标签中,并使用进度条显示已查看的选定站点的数量。

Private Sub GetFeed(ByVal i As Integer)
    On Error GoTo Errsub
    Dim strUrl As String
    Dim dr As DataRow
    'Select the row (base 0) from the viewitems dataset
    dr = Me.DataSet11.ViewItems.Rows(i - 1)
    strUrl = dr.Item("link").ToString
    'Navigate to the site and display in browser
    webBrowser0.Navigate(strUrl)
    'Item being displayed in browser
    Me.lblPosition.Text = intItemViewed.ToString & " of "_
       & intItemstoView.ToString & " items. " & _
       webBrowser0.LocationURL.ToString
    Exit Sub
ErrSub:
    MsgBox(Err.Description & " in GetFeed Procedure. ", _
                        MsgBoxStyle.Information, "Error")
End Sub

用户可以使用“下一个/上一个”按钮、浏览器菜单面板下的菜单项或功能键从一个选定的新闻项目导航到下一个。功能键 F11 和 F12 通过菜单项属性页中的快捷方式属性映射到浏览器菜单面板中的菜单项。

Private Sub procNextPage()
    ' If the page being viewed is not the last page, view next page
    If intItemViewed < intItemstoView Then
        intItemViewed = intItemViewed + 1
        GetFeed(intItemViewed)
        pgsBrowser.Value = intItemViewed
    Else
        MsgBox("Last Item Displayed", MsgBoxStyle.Information, "Error")
    End If
End Sub

窗体级变量 intItemViewed 递增,并使用 GetFeed 方法在浏览器中显示相应的项目。类似的代码用于导航到上一页。

用户可以通过在“新闻项目”菜单项中进行适当的选择来删除 item 表中的项目。请注意,在从数据库中删除项目之前使用额外的验证,以防止意外删除。

MsgResult = MessageBox.Show("Items NOT selected will be deleted" & _ 
   " from the database. Do you want to proceed?", "Data Base Deletion", _
   MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning)

MessageBox.Show 方法返回 DialogResult 类型的值,该值可用于确定用户对 MessageBox 的响应。此处使用的消息框是“是/否/取消”类型的消息框,它包含一个警告图标,用于告知用户选择的重要性。

If MsgResult = DialogResult.Yes

只有当用户点击“是”选项时,代码才会继续删除数据。

MyCommand.CommandText = "Delete from Item where view = False"

该命令设置为一个 SQL 语句,该语句将删除所有未选择查看的项目。如果父连接未打开,则打开并使用它。该命令在使用后被清除,并且 DataSet 被刷新以显示新的更新数据。DataGrid 也使用新数据进行刷新。

Me.DataSet11.item.Clear()
Me.OleDbdaItem.Fill(Me.DataSet11.item)
Me.dgdItems.Refresh()
Private Sub mnuDeleteItemsNotSelected_Click(ByVal sender As _
        System.Object, ByVal e As System.EventArgs) _
        Handles mnuDeleteItemsNotSelected.Click
    Dim MsgResult As DialogResult, intRowsAffected As Integer
    ' Warning message before deleting items from the database
    MsgResult = MessageBox.Show("Items NOT selected will be " & _ 
                "deleted from the database. Do you want to proceed?", _
                "Data Base Deletion", MessageBoxButtons.YesNoCancel, _
                MessageBoxIcon.Warning)
    'Proceed only after user confirmation
    If MsgResult = DialogResult.Yes Then
        ' save view item state in database
        'This saves the current state of the items table, 
        'and records user selections before deleting
        ' items not selected for viewing
        'If this is not done, then the delete command 
        'will remove items selected for viewing as well
        Me.OleDbdaItem.Update(Me.DataSet11.item)
        Dim MyCommand As New OleDb.OleDbCommand
        MyCommand.CommandText = "Delete from Item where view = False"
        If Me.OleDbConnection1.State <> ConnectionState.Open Then
            Me.OleDbConnection1.Open()
        End If
        MyCommand.Connection = Me.OleDbConnection1
        intRowsAffected = MyCommand.ExecuteNonQuery()
        MyCommand.Dispose()
        'Clear dataset and fill it with new, updated item table from database
        Me.DataSet11.item.Clear()
        Me.OleDbdaItem.Fill(Me.DataSet11.item)
        Me.dgdItems.Refresh()
    End If
End Sub

“帮助”菜单项显示开发者的网站以获取帮助信息。我更喜欢这种方式,而不是构建 WinHelp 或 HTML 帮助文件来与程序打包。这会将所有帮助查询收集到一个集中式站点,并帮助我根据用户请求不断更新帮助。

Private Sub mnuWebHelp_Click(ByVal sender As System.Object, _
         ByVal e As System.EventArgs) Handles mnuWebHelp.Click
    ' Help on web site 
    webBrowser0.Navigate("http://mang.uno.edu/RssReader")
End Sub

“关于”菜单项显示程序的版本、版权和其他相关信息。请注意,您首先必须确保此信息已输入到项目中的 assemblyInfo.vb 文件中。创建 Assembly 和版权对象,并将其值设置为程序的对应值。vbCrLf 在消息框字符串中提供换行符。

Private Sub mnuAbout_Click(ByVal sender As System.Object, _
           ByVal e As System.EventArgs) Handles mnuAbout.Click
  Dim asmbly As System.Reflection.Assembly
  Dim copyright As System.Reflection.AssemblyCopyrightAttribute
  asmbly = System.Reflection.Assembly.GetExecutingAssembly
  copyright = _
   asmbly.GetCustomAttributes(GetType(System.Reflection.AssemblyCopyrightAttribute),_
   False)(0)

  MsgBox("Product: " & Application.ProductName & vbCrLf & _
           "Version: " & Application.ProductVersion.ToString & _
           vbCrLf & "Copyright:  " & copyright.Copyright.ToString, _
           MsgBoxStyle.Information, "About")
End Sub

AssemblyInfo.vb 文件是一个文本文件。它需要具有精确的语法才能正常工作。

<Assembly: AssemblyTitle("Rss Reader")> 
<Assembly: AssemblyDescription("Rss Reader - Vb.Net")>
<Assembly: AssemblyCompany("")> 
<Assembly: AssemblyProduct("")> 
<Assembly: AssemblyCopyright("Sathi Mahesh:  May 2, 2005")>

属性设置为您想要的值。

<Assembly: AssemblyVersion("1.0.*")>

AssemblyVersion 属性设置为版本、发布和构建。构建的 * 允许 VS.NET 自动设置构建值。

参考文献:艾萨克·牛顿曾说:“我之所以能看得更远,是因为我站在巨人的肩膀上。”。我用牛顿的话来形容我的编码,可以说我能写出这么多代码,只是因为我“剪切并粘贴”了别人的代码。考虑到我为了让代码正常运行而进行的 Google 搜索,任何参考文献列表都不会是完整的。但是,我必须提供一份在我编写此代码时对我帮助最大的参考文献列表。在不否认许多其他人的贡献的情况下,这些参考文献对于这项工作来说意义重大。

© . All rights reserved.