基於ASP.NET AJAX技術開發線上RSS閱讀器(下篇)

來源:互聯網
上載者:User

五、邏輯層設計

(一)添加RSS頻道

在展開真正的邏輯層設計之前,先讓我們簡單地瀏覽一下下面的草圖4。圖4展示了我對於兩個重要ASP.NET AJAX用戶端控制項—ListView和DataSource以及MS AJAX官方資料中建議的實現用戶端資料繫結架構的理解。

圖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所示。

圖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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.