基于ASP.NET AJAX技术开发在线RSS阅读器

内容摘要:本文旨在通过一个简单的在线RSS阅读器的开发过程探讨基于微软ASP.NET AJAX框架(特别是客户端技术)进行新一代ASP.NET 2.0开发所涉及的典型问题。本文章分为两个部分,上篇介绍本软件中的数据层与描述层部分。在下篇中,我们转入整个开发过程的重点—逻辑层的设计。

  【注】本文测试环境:Windows XP专业版+Visual Studio 2005+整套ASP.NET AJAX框架+ASP.NET RSS Toolkit+SQL Server 2005。

  一、RSS技术简介

  RSS是一种描述和同步网站内容的XML格式,已经成为越来越流行的网站内容订阅技术。通过这种技术,网站可以极大地提高广大网站用户和网站数据之间的数据交互。

  RSS阅读软件可以分为桌面离线式和在线式两大类。有了这种工具,用户只需要添加初始其所关注的RSS网址,以后系统会自动更新相关内容,网友只需静待观察自己感兴趣的新闻即可。

  目前存在多种版本的RSS文件格式,有0.90、0.91、0.92、0.93、0.94、1.0和2.0。其中,最为流行的是2.0版本。下面展示了一个最简单的2.0版本的RSS文件的基本格式:

<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>Example Channel</title>
<link>http://example.com/</link>
<description>My example channel </description>
<item>
<title>News for September the Second</title>
<link>http://example.com/2002/09/01</link>
<description>other things happened today</description>
</item>
<item>
<title>News for September the First</title>
<link>http://example.com/2002/09/02</link>
</item>
</channel>
</rss>

  由上可以,RSS文件的主要节点有rss,频道和item等。其中rss节点表示执行的RSS标准命名空间;频道节点表示在博客或新闻组中的一个类别,通常被译为频道;item节点是用户要查看的主要信息,其中包括信息的标题、信息内容的链接地址及信息的发布时间等。有关RSS文件的完整节点介绍,请参考网址http://cyber.lay.harvard.edu/blogs/gems/tech/rss2sample.xml。

  关于Robsman的ASP.NET RSS Toolkit

  很显然,因RSS文件版本繁多,而且存在一定差距,如果手动解析XML文件费时费力。还好,我们可以利用微软公司开发的开源RSS Toolkit工具包(下载网址:http://blogs.msdn.com/dmitryr/)来简化之。

  这个工具包具有如下功能:

  1)RSS数据源控件—其使用方式与ASP.NET内置的数据源控件一样,它也支持绑定和支持模板化数据绑定,并为其提供显示所需的数据;

  2)可以在内存或磁盘中缓存远程RSS提要对应的内容;

  3)基于RSS的URL地址为RSS提要生成易于开发调试的强类型对象;

  4)对程序中生成的RSS提要相应的典型操作进行封装。

  下面,我们通过一个具体的例子来探讨如何使用这个工具包并基于微软ASP.NET AJAX框架来开发一个简单的RSS新闻阅读器。

  二、本系统主要功能及关键技术分析

  在正式开工以前,让我们先来了解一下本系统要实现的主要功能以及开发本系统所涉及的主要技术。

  (一)主要功能

  一个在线RSS阅读器可以把你喜欢的RSS订阅存储在服务器端数据库中以便后来在方便之时在具有因特网连接的任何位置进行访问。典型地,我们可以通过下图1来大致描述一个RSS阅读器的工程流程。

基于ASP.NET AJAX技术开发在线RSS阅读器(上篇)

  图1:一个RSS阅读器的典型工程流程

  根据上面的示意图,我们的RSS阅读器示例工程DAjaxRssReader将主要实现以下目标:

  ◆添加RSS频道

  用户可以把其新输入的RSS频道以及相关的URL信息保存到ASP.NET AJAX客户端数据源控件中。并且当然,他们能够把所有这些信息存储到远端的服务器SQL Server数据库中。

  ◆显示所有RSS频道

  这主要包括两种情况:1、当应用程序首先启动时所有的存储于服务器端数据库中的频道信息都应该能够列出于浏览器端;2、当用户刷新RSS频道时,所有的与频道相关联的数据都可以从服务器端读回并显示于客户端。

  ◆显示选择的特定RSS频道的详细信息

  当用户选择某个频道时,应用程序应该能够展示出相应的与该频道相链接的特定网页内容。

  (二)关键技术

  首先,在开发任何典型的Web应用程序的过程中,我们都应尽可能地遵循著名的三层结构原则。下图的图2展示了本文中的RSS阅读器程序相应的三层架构略图。

基于ASP.NET AJAX技术开发在线RSS阅读器(上篇)

  图2:本文RSS阅读器程序的整体架构示意图

  接下来,在正式讨论所涉及的关键技术之前,让我们快速地浏览一下示例程序主页面的快照,如下面图3所示。

基于ASP.NET AJAX技术开发在线RSS阅读器(上篇)

  图3:本文示例RSS阅读器程序设计时刻快照

  根据上面所展示的图形及前面的功能分析,我们大致需要基于以下关键技术来开发本文中的应用程序:

  1、在描述层,我们需要使用ASP.NET AJAX客户端ListView控件来存储并显示所有RSS频道信息,还有一个服务器端UpdatePanel控件来封装上图中的ASP.NET AJAX Control Toolkit控件Accordion以便最终显示与你从ListView中点选的项相关联的网站内容。此外,我们还需要一点CSS技巧来修饰所有相关的控件。最后,我们还引入了ASP.NET AJAX客户端校验器(Validator)来实现对用户输入的RSS名字和URL的校验功能。

  2、在本文示例程序中,我们将混合使用JavaScript与xml-script声明性编程方式。一方面,在实际开发环境下,基于ASP.NET AJAX框架的Web应用程序通常是相当复杂的;另一方面,ASP.NET AJAX框架本身也还没有完全成熟起来以便使我们的构建目标完全基于xml-script声明性编程方式进行开发。尽管实现在实现某些编程时使用JavaScript方式相对xml-script声明性方式相对更复杂一些(因为ASP.NET AJAX客户端提供了十分类似于ASP.NET的声明性编程方式),但是,JavaScript方式的好处在于,它能够控件开发过程中从服务器端到客户端的每一个方面。

  3、对于基于ASP.NET AJAX应用程序的数据层开发而言,在线资料中已经提供了典型的实现模式,本文示例将秉承这一模式。

  【作者注】在调试本文示例程序时,我被因引入ASP.NET AJAX Control Toolkit控件并结合Dmitry Robsman的ASP.NET RSS Toolkit所带来的客户端与服务器端通讯的问题所困扰。根据我的分析,通常情况下,我们无法在一个Web服务内部实现把服务器端的RssDataSource(RSS.NET Toolkit中的一个类)动态地绑定到Accordion控件(实际上是一个ASP.NET AJAX服务端扩展器)。因此,为了克服这一难题,我不得不求助于__doPostBack函数来创建客户端与服务器端的连接;这明显会引发一个整面刷新的问题—这与ASP.NET AJAX规则是根本相冲突的。为此,我不得不引入了ASP.NET AJAX服务器控件UpdatePanel来把Accordion控件“包围”起来以便实现局部更新效果。当然,使得事情进一步复杂化的另一个因此还在于ASP.NET AJAX客户端控件—ListView。从较底层的分析来看,这个ListView控件还远远没有成熟起来!

  下面,让我们从数据层设计开发逐步探讨整个示例工程的开发过程。

  三、数据层设计

  (一)数据库设计

  启动Visual Studio 2005,选择“文件→新建网站…”,然后选择“ASP.NET AJAX-Enabled Web Site”模板,命名工程为“AjaxRss”,并选择C#作为内置支持语言,最后点击OK。注意,此后系统将自动加入对于程序集Microsoft.Web.Preview.dll和System.Web.Extensions.dll的引用。当然,你还会注意到,作为ASP.NET AJAX司令部的服务器控件ScriptManager被自动地添加到默认网页Default.aspx中。

  现在,请右击工程,选择“添加新项…”,然后选择模板“SQL Database”创建一个命名为RssReader.mdf的空数据库。在本文应用程序中,我们仅在此库中添加一个表格RssStore(其所有字段都显示于下面的表格1中)。此后,我们还要创建四个存储过程:DeleteRecord,GetAllRecords,InsertRecord和UpdateRecord。这四个存储过程分别相应于典型的数据库CRUD操作(ASP.NET AJAX客户端数据绑定技术对此提供了较好的支持方案,本文中即展示之)。所有这些内容在此我们不去赘述。

  表格1:表格RssStore相应的结构

  字段名

类型
说明

Rss_ID
int
表格主键

Rss_Name
nchar(32)
RSS频道名字

Rss_URL
nchar(64)
RSS频道URI(或者URL)

  (二)Web服务设计

  接下来,我们要编写一个将从客户端以AJAX方式进行调用的Web服务。在本文示例中,我们让该服务返回一个RssInfo对象(用作数据库表格RssStore中记录的OOP包装器)数组。

  现在,请以鼠标右击工程并选择“添加新项…”创建一个新的Web服务MyDataService.asmx。然后,打开文件BookDataService.cs,在其中编写我们要求的所有的Web方法—DeleteRecord,GetAllRecords,InsertRecord和UpdateRecord。这四个方法与我以前在51CTO上发表的文章中所涉及的基本一致,在此不多赘述。有兴趣的读者也可参考本文相应源码加以分析。

  下面,我们将进入到用户接口设计阶段。

  四、用户接口层设计

  根据上面介绍的一般框架,我们可以把整个用户接口部分划分成三个子部分:

  1)添加新的RSS频道信息;

  2)显示RSS频道列表;

  3)显示指定的RSS频道内容(即与之相关联的网站内容)。

  上面给出的图3已经显示了本文应用程序的设计时刻的用户接口。

  在上面的图3中,位于左上角的是一个ASP.NET AJAX客户端控件—ListView;它用于存储和显示RSS频道列表。其下方的.gif动画(注:它相应于控件ListView的emptyTemplate模板部分)仅仅是为了产生一种更为友好的用户体验效果。动画页面的那个较大的矩形区(它包含简单若干个简单的ASP.NET AJAX客户端控件)域对应一个HTML div标签(名为“buttonarea”),提供给用户输入新的RSS频道信息。整个Web页面的右部是一个ASP.NET AJAX Control Toolkit中的Accordion控件,它用于显示指定RSS频道的详细信息。有关于页面中的另外几个“神秘”的小点与包围Accordion控件的ASP.NET AJAX服务器控件UpdatePanel及与之相关联的UpdateProgress控件,我们将在后面详细介绍。现在,你肯定注意到了位于页面最左下角的Rss Toolkit control—RssDataSource控件,它用于从服务器端为Accordion控件提供数据源(一般来说,我们仅能在运行时刻从服务器端使用它,因为它是一个服务器端数据源控件。关于这个控件的细节,后面我们还要介绍)。最后,所有的控件都被使用一个HTML table元素进行包围。

  到此为止,我们已经介绍完本软件中的数据层与描述层部分。在下篇中,让我们转入整个开发过程的重点—逻辑层的设计。

五、逻辑层设计

(一)添加RSS频道

在展开真正的逻辑层设计之前,先让我们简单地浏览一下下面的草图4。图4展示了我对于两个重要ASP.NET AJAX客户端控件—ListView和DataSource以及MS AJAX官方资料中建议的实现客户端数据绑定架构的理解。

498)this.style.width=498;">

图4:ASP.NET AJAX框架中建议的典型的客户端数据绑定架构

从上图中,我们可以得出如下结论:在实战环境(本例中也是如此)下,当添加一个新的RSS频道时,我们并不需要立即把这些数据存储到服务器端的SQL Server数据库中,而是暂时存储到与客户端控件ListView相关联的数据源控件中。因此,你可以已经猜出,该DataSource控件是支持批更新操作的—支持对于客户端修改数据的临时存储并最终以批处理方式实现更新服务器端数据库。上面草图中的两个重要方法—“Save”和“Load”在此实现逻辑中起着重要作用。

在这一节中,我们仅需要在客户端临时存储用户新输入的RSS频道信息。在此,我在操作ListView控件的过程中遇到了第一个难题。下面先让我们来看一下相应的源码。

列表1

<script language="javascript" type="text/javascript">

var g_RSSNameList;

function pageLoad(sender, args) {

g_RSSNameList=$find('RSSNameList');

…………

}

function Add_onclick() {

g_RSSNameList.addItem();

var  index=datatable.get_length()-1;

datatable.getItem(index).setProperty('Rss_ID', index);

datatable.getItem(index).setProperty('Rss_Name', $find('txtRssName').get_text());

datatable.getItem(index).setProperty('Rss_URL', $find('txtRssUrl').get_text());

}

当用户点击客户端HTML Input按钮“Add the RSS Info”时将调用上面的JavaScript函数Add_onclick(即click事件处理器)。在此,g_RSSNameList是一个全局JavaScript变量,它引用了ListView“RSSNameList”(即负责存储和显示与RSS频道信息的控件)。在这个函数中,我们首先调用ListView的addItem方法;此方法能够把一条空记录添加在与DataSource控件关联的DataTable控件的最后,同时还能够使数据集变脏(这一点对于后面我们将讨论的“保存”操作至关重要)。然后,我们得到此空记录的记录号。然后,我们调用方法getItem(这个方法与方法getRow完全一致)取回空记录并调用方法setProperty来填充相应的数据库表格字段。注意,在此,我们必须使用客户端全局方法$find而不是$get;有关其间的差异请参考框架在线资料。最终,我们实现了在客户端数据源中插入(即‘添加’)一条记录。

注意,在此,我使用了最简单的ASP.NET AJAX客户端校验器组件—requiredFieldValidator来防止用户不在文本框内输入内容。下面是相应的xml-script代码声明。

列表2

            

<textBox id="txtRssName">

<validators>

<requiredFieldValidator errorMessage="You must name the RSS!" />

</validators>

</textBox>

<validationErrorLabel id="validator1" associatedControl="txtRssName" />

<textBox id="txtRssUrl">

<validators>

<requiredFieldValidator errorMessage="You must name the Url of the RSS!" />

</validators>

</textBox>

<validationErrorLabel id="validator2" associatedControl="txtRssUrl" />

在此,在第二个文本框架控件的校验中,你可以选用更好一些的校验器控件regExValidator(它能够利用正规表达式对这里的url进行格式校验)。如果你让两个控件空着(例如仅输入几个空格字符),那么,系统将显示一个红色的“*”号—示意你应该输入一些数据。在调试此程序时,当我保持此两个文本框为空(不输入任何内容),系统看上去毫无反映。这怀疑这是客户端校验器Validator中存在的一个小小的BUG,有兴趣的读者可作进一步分析。

【作者注】在本文演示程序中,我没有实现“删除”和“修改”功能。在此,我强烈建议读者试着加入这两个功能。通过这些操作,你的ASP.NET AJAX客户端编程功力将得到极大提升。

接下来,让我们探讨如何显示存储于服务器端的RSS隧道的问题。

(二)显示RSS频道

在这一部分中,要显示RSS频道,存在至少两种情形:

1)当页面初次加载时,所有存储于服务器端SQL Server数据库中的RSS频道都将显示于前面我们提到的客户端控件ListView中;
2)当用户点击按钮“Refresh”时,所有原始的存储于服务器端SQL Server数据库中的RSS频道信息都被显示于客户端控件ListView中。

现在,首先让我们来分析第一种情形。下面的列表显示了相应的xml-script声明性代码。

列表3

            

<script type="text/xml-script">

<page xmlns:script="http://schemas.microsoft.com/xml-script/2005">

<components>

<dataSource id="RSSInfoDataSource" serviceURL="MyDataService.asmx" >

</dataSource>

<button id="Save">

<click>

<invokeMethodAction target="RSSInfoDataSource" method="save" />

</click>

<bindings>

<binding dataContext="RSSInfoDataSource" dataPath="isDirtyAndReady"

property="element" propertyKey="disabled" transform="Invert" />

</bindings>

</button>

<button id="Refresh">

<click>

<invokeMethodAction target="RSSInfoDataSource" method="load" />

</click>

<bindings>

<binding dataContext="RSSInfoDataSource" dataPath="isReady" 

property="element" propertyKey="disabled" transform="Invert" />

</bindings>

</button>

<application>

<load>

<invokeMethodAction target="RSSInfoDataSource" method="load"/>

</load>

</application>

</components>

</page>

</script>

在此,我们首先指定DataSource控件“RSSInfoDataSource”。这个控件将被ASP.NET AJAX框架以异步方式绑定到服务器端DataService“MyDataService”。其次,在最后面的<application>节中,当该Web应用程序启动时,它相应的load事件方法被调用。然后,在子节<invokeMethodAction>中,数据源“RSSInfoDataSource”的load方法被调用,这将触发一次异步回寄—调用数据服务“MyDataService”的Web方法GetAllRecords。下面的列表展示了这个方法的实现代码。

列表4

[WebMethod]

[DataObjectMethod(DataObjectMethodType.Select)]

public List<RssInfo> GetAllRecords()

{

return new SqlTaskProvider().GetAllRecords();

}

有关于此方法之前的修改属性,在此不多赘述,请参考ASP.NET AJAX在线文档。现在,一旦这个方法执行结束,客户端ListView控件“RSSNameList”即被以存储于服务端SQL Server数据库表格RssStore中的记录所填写。

注意,在此我们略微施了点小技:为了取得较好的用户体验感,我们隐藏了两个字段Rss_ID和Rss_URL(这两个字段中的内容是不需要显示的)。下面给出的是相应的HTML代码片断。

列表5

<div id="searchResults_itemTemplate" >

<span id="searchResults_Rss_ID" style="display: none; visibility: hidden;"></span>

<span id="searchResults_Rss_Name"></span>

<span id="searchResults_Rss_URL" style="display: none; visibility: hidden;"></span>

</div>

不必我们担心,ASP.NET AJAX框架会自动区分这一情形,并仍然能够以数据库记录数据填充ListView控件,只不过是隐藏了其中两个字段的显示而已。

现在,让我们来分析第二种情形—当用户点击按钮“Refresh”时。尽管从字面上看,我们使用的是“Refresh”(即“刷新”),但是这个按钮的真正作用是把服务器端的数据库数据加载到当前ListView控件中。这一过程与客户端的数据控件DataSource存在着直接的联系。下面的xml-script代码向你展示了相应的编程。

列表6

            
<button id="Refresh">

<click>

<invokeMethodAction target="RSSInfoDataSource" method="load" />

</click>

<bindings>

<binding dataContext="RSSInfoDataSource" dataPath="isReady" 
     property="element" propertyKey="disabled" transform="Invert" />

</bindings>

</button>

从上面的代码可知,当用户点击按钮“Refresh”时,客户端DataSource控件“RSSInfoDataSource”的方法load被调用。然后,Web方法GetAllRecords将被异步调用;最后此Web方法返回的数据被填充到ListView控件中。

为了完整起见,在本示例程序中,我们还引入了一个“Save”按钮,其功能与按钮“Refresh”恰恰相反。当用户点击按钮“Save”时,所有位于ListView控件中的最新的RSS频道数据都将被以AJAX方式(即“异步”方式)永久性存储到服务器端的SQL Server数据库中。要想进一步探讨这个按钮的作用机制,请参考我发表在51CTO上的另一篇文章“”;在此文章中,我较为全面地分析了ASP.NET AJAX客户端ListView和ItemList控件等与以Web服务包装下的服务端SQL Server数据库的交互。

(三)显示指定RSS频道相应内容

现在,问题变得越来越有趣了。为了显示一个RSS频道的内容,为仅需要点击ListView控件中一项,然后让右边的Accordion控件展示相应的细节信息,不就行了?不错,但这仅是从用户角度得到的结论。但作为开发人员,为了解决这个问题,我花费了大量时间才找到一种实现方案。下面,让我来逐一向各位介绍。

通过网络取得RSS频道内容

1、关于ListView控件

有关ASP.NET AJAX框架提供的“高级”客户端ListView控件,我想先简单地讨论几句。从研究框架相应的源码文件PreviewScript.js,我们发现在这个控件的descriptor块定义(注:只在位于此块中的内容才可能在xml-script声明性编程方式中使用)中仅提供了极少数目的属性,方法与事件定义。下列我们干脆列出这个控件的descriptor块的定义。

列表7

Sys.Preview.UI.Data.ListView.descriptor = {

properties: [ { name: 'alternatingItemCssClass', type: String },

{ name: 'layoutTemplate', type: Sys.Preview.UI.ITemplate },

{ name: 'itemCssClass', type: String },

{ name: 'itemTemplate', type: Sys.Preview.UI.ITemplate },

{ name: 'itemTemplateParentElementId', type: String },

{ name: 'selectedItemCssClass', type: String },

{ name: 'separatorCssClass', type: String },

{ name: 'separatorTemplate', type: Sys.Preview.UI.ITemplate },

{ name: 'emptyTemplate', type: Sys.Preview.UI.ITemplate } ],

events: [ {name: 'renderComplete'} ]

}

在上面的descriptor块定义中,仅有几个有限的属性和一个事件。后面我们将使用的方法,还要求助于控件的父类DataControl。为此,为能够控制用户点击的ListView控件中的每一项(对应一条记录数据),我们不得不进一步研究ListView控件定义中的prototype块,并进而求助于JavaScript编程。

2、通过JavaScript编程为ListView添加事件

首先,让我们列出与上面所有相应的源码部分。

列表8

            

<script language="javascript" type="text/javascript">

var g_RSSNameList;

function pageLoad(sender, args) {

g_RSSNameList=$find('RSSNameList');

$addHandler($get('RSSNameList'), 'click', clickRowHandler);

}

function clickRowHandler(ev)

{

var s = ev.target;

while (s && (typeof(s.dataIndex) === 'undefined')) {

s = s.parentNode;

}

if (s) {

var idx = s.dataIndex;

//调用与“哑元”控件dummySrvBtn相应的服务器端方法

var btn ='<%=dummySrvBtn.ClientID%>';

var txt='<%=txtRssUrl2.ClientID%>';

document.getElementById(txt).value="/s.lastChild.innerText;"

__doPostBack(btn,'');

}

}

……(省略)

function pageUnload() {

//释放事件处理器

if (clickRowHandler)

$removeHandler($get('RSSNameList'), "click",clickRowHandler);

clickRowHandler=null;

}

在此,我们首先使用全局方法$addHandler来把事件处理器clickRowHandler关闻到ListView控件RSSNameList的click事件上。接下来,我们来分析这个事件处理器函数的编程。一开始,属性ev.target指向ListView RSSNameList。当程序执行到if条件语句时,变量s指向searchResults_itemTemplate(数据库记录正是在其中显示)。现在,我们可以使用变量idx来取得记录索引的当前值并且可以获取我们想取回的任何字段值(在此,我们仅对最后一个字段Rss_URL感兴趣)。

情况到现在变得越来越复杂了—我们怎样才能为RssDataSource控件(注意这是一个第三方服务器端数据控件)动态地指定RSS url呢?在此,我的方案是求助于方法“__doPostBack”。根据本文分析,一般情况下,我们无法在一个Web服务方法内实现把RssDataSource动态地绑定到Acccordion控件。这样以来,我们只取另寻出路—CodeFile文件AjaxRssReader.aspx.cs。试验证明,在这个后台文件中,我们可以实现上面的目标—把RssDataSource动态地绑定到Acccordion(注意,我们无法在客户端JavaScript脚本中实现这一绑定,因为这是一个服务器端数据源控件)。这也正是我们求助于__doPostBack方法的原因,借助于这个方法,我们可以间接地实现客户端控件与服务器端控件的通讯。

为了实现上面的目标,现在,我们要创建两个“哑元”ASP.NET控件(这仅是我的思路)—一个Button控件和一个TextBox控件。由于它们在运行时刻必须是不显示的,所以我们把它们的尺寸设置为最小值(宽高均为1个像素X),并相应地把其背景设置为浅灰色(这正好相应于按钮区域“buttonarea”的背景色)。

【作者注】在试验中,我发现我们无法把两个“哑元”控件的Visible属性设置为false;否则,将出现运行时刻错误。

接下来,通过调用方法“__doPostBack”我们间接地调用了服务器端click事件处理器—dummySrvBtn_Click(object sender,EventArgs e)(此函数位于CodeFile文件AjaxRssReader.aspx.cs内)。下面是这个函数相应的源码。

列表9

protected void dummySrvBtn_Click(object sender, EventArgs e)

{

RssDataSource1.Url = txtRssUrl2.Text.Trim();

Accordion1.DataSourceID = "RssDataSource1";

Accordion1.DataBind();

}

现在,我们先略过对这段代码的分析。

然后,通过把字段Rss_URL的值赋为相关联的HTML Input元素txtRssUrl2.ClientID(对应ASP.NET服务器端Id—txtRssUrl2)的attribute值(对应于对应服务器端的Text属性),我们就成功地实现了把数据从客户端传输到服务器端。

最后,调用方法“__doPostBack”将必然导致一次整个页面的刷新—这与AJAX基本思想是根本相违背的。这正是我们引入ASP.NET AJAX服务器控件UpdatePanel(它把Accordion控件相应的区域包围起来)的原因。注意,在此我们使用UpdatePanel的AsyncPostBackTrigger触发器来实现使按钮“dummySrvBtn”的click事件触发UpdatePanel的刷新操作。下面是相关的HTML代码部分。

列表10

<asp:UpdatePanel ID="UpdatePanel1" runat="server">

<Triggers>

<asp:AsyncPostBackTrigger ControlID="dummySrvBtn" EventName="Click" />

</Triggers>

<ContentTemplate>

<ajaxToolkit:Accordion ID="Accordion1" CssClass="myAccordion" HeaderCssClass="header"

…………(省略)

也因此,我们才引入了服务器控件UpdateProgress来配合UpdatePanel控件取得更友好些的用户体验。

也许我上面的方案太“丑陋”了;因此,非常希望热心读者能够进一步改进之。

显示频道内容

到目前为止,这一步已经变得相当简单了。事实上,在上面的源码9中我们已经实现了这一目标。通过对于控件RssDataSource1的属性Url的动态赋值,然后把它绑定到控件Accordion1,进而调用Accordion1的方法DataBind,我们最终实现根据用户点击的频道标题信息显示该频道的具体网页内容。

【作者注】第一,通过Google搜索因特网,我竟然没有发现实现RssDataSource控件动态赋值的相关示例。第二,由于某些RSS内容中可能不包含author字段,所以我干脆在控件Accordion的<ContentTemplate>块中注释掉此字段。

最后,让我们来看一下我们的最终成果吧,如下图5所示。

498)this.style.width=498;">

图5:在用户点击RSS频道“Scott Guthrie”后的示例程序运行时刻快照

六、总结

在本文中我们使用微软ASP.NET AJAX框架开发了一个简单的RSS阅读器程序。作为一个演示程序,我们仅为了探讨这个框架的基本使用思路;所以,此软件还存在许多地方有待改进:

1)仅使用ASP.NET AJAX客户端技术开发
2)进一步探讨实现客户端与服务器通讯的其它方式
3)使用客户端控件XSLTView控件来取代本文所使用的ASP.NET AJAX Control Toolkit控件Accordion来显示RSS频道内容
4)使用客户端控件Validator—regExValidator来更为严格地校验用户输入的RSS频道地址
5)进一步支持用户在运行时刻实现对RSS频道信息的删除/修改
6)增加另外的类型RSS并且为用户提供分类管理
………

有兴趣的朋友可以根据上面这些提示进一步改进本文示例。
原文地址:http://developer.51cto.com/art/200708/53158_3.htm

posted @ 2009-12-21 13:04  貔貅  阅读(387)  评论(0编辑  收藏  举报