控制項|語句 我最近正在寫一個 BBS 的項目,在顯示主題列表時,我遇到了一個問題。 BBS_Topic 的資料表結構定義大致是下面這樣:
TABLE BBS_Topic
(
TopicID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
Title NVARCHAR(40),
Author NVARCHAR(20),
PostDate DATETIME NOT NULL DEFAULT GETDATE(),
Content NTEXT,
Clicked INT NOT NULL DEFAULT 0,
ReCount INT NOT NULL DEFAULT 0,
LastReplyer NVARCHAR(20)
)
下面是ListTopic.aspx檔案中的部分內容:
<asp:Repeater ID="_TopicRepeater" Runat="SERVER" DataSource="...">
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, "Title") %>
<%# DataBinder.Eval(Container.DataItem, "Author") %>
<%# DataBinder.Eval(Container.DataItem, "Clicked") %>
<%# DataBinder.Eval(Container.DataItem, "ReCount") %>
<!-- 注意下面的if語句 -->
<% if((int)(DataBinder.Eval(Container.DataItem, "ReCount"))==0){ %>
----
<% } else { %>
<%# DataBinder.Eval(Container.DataItem, "LastReplyer") %>
<% } %>
</ItemTemplate>
</asp:Repeater>
使用if語句的目的是在於:判斷當前文章的回複次數為 0 時,就將 LastReplyer 這項顯示成“----”。而當前的文章的回複次數不為 0 時,則顯示回複人的名字。但是,這樣的做法是行不通的。在IE中會出現類似的警告
編譯器錯誤資訊: CS0246: 找不到類型或命名空間名稱“Container”(是否缺少 using 指令或程式集引用?)
即便,根據這個錯誤提示,將所有可能用到的命名空間全都 Import 到這個檔案裡,也還是會提示其他錯誤資訊的。至於為什麼這樣?可能是因為 DataBinder.Eval 和 Container.DataItem 同屬 Repeater 類的成員的緣故。 “<%# %>”就是“作用”在 Repeater 上,但是 “if ... else ...” 語句則不同,它是“作用”在整個頁面上。這就象是在全域過程中直接存取局部變數。當然,用類似下面(三目運算)的語句也可以實現上述功能:
<%# ((int)(DataBinder.Eval(Container.DataItem, "ReCount"))==0)
? "----"
: DataBinder.Eval(Container.DataItem, "LastReplyer") %>
可問題是,對於複雜的判斷處理,這樣的做法就相當困難了。
而 <%# if ... else ... %> 這樣的用法又為什麼也不行呢?因為 <%# %> 相當於 <%= %>,而 <%= %> 就是 Response.Write(),那麼前面的判斷就顯得可笑:
Response.Write( if ... else ... );
如果非要在 Repeater 中使用 if 語句來判斷其中的資料,那麼可以採用下面的方法:
<% int _nIndex=0; %> <!--定義一個臨時的整型變數-->
<asp:Repeater ID="_TopicRepeater" Runat="SERVER" DataSource="...">
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, "Title") %>
<%# DataBinder.Eval(Container.DataItem, "Author") %>
<%# DataBinder.Eval(Container.DataItem, "Clicked") %>
<%# DataBinder.Eval(Container.DataItem, "ReCount") %>
<%
int nReCount=(int)(((DataView)_TopicRepeater.DataSource).Table.Rows[_nIndex++]["ReCount"]);
// 也可以分成幾句來寫
// DataView DV=(DataView)_TopicRepeater.DataSource;
// DV.Table.Rows[_nIndex++]["ReCount"];
if(nReCount==0) { %>
----
<% } else { %>
<%# DataBinder.Eval(Container.DataItem, "LastReplyer") %>
<% } %>
</ItemTemplate>
</asp:Repeater>
其基本思路是,得到 _TopicRepeater 的資料來源(DataSource)
(註明:我在綁定 Repeater 的資料來源時,使用的是 DataSet.Tables["..."].DefaultView。如果使用的是其他的資料來源,那麼在給 Repeater.DataSource 強制轉型時,要稍加註意)
並返回該表(Table)的當前行(Rows[_nIndex++])最後判斷 ReCount 列是否為 0?在最初的時候 _nIndex 被賦值為 0,然後,在每一次的 ItemTemplate 裡都自加一次。其目的,也就是讓 _nIndex 記錄當前正在訪問的記錄“行”。
對於DataGrid和DataList,這個方法也是可行的。
最後,這個方法在進行複雜判斷綁定資料時確實有效,但是我並不推薦這樣的做法!因為這樣的做法並不符合物件導向的封裝特性,或者說,它是以破壞了封裝特性的做法使之透明,來完成判斷功能的。 我推薦的做法是,使用“自訂使用者控制項”來完成複雜的判定綁定任務。