asp.net ListView控件用法簡介

ListView 基礎
ListView 是模板驅動的控件,這意味着它默認情況下不會呈現任何數據——您必須以模板的形式完全指定希望它呈現的 HTML。與大多數模板控件類似,ItemTemplate 將成爲您工作的重點,您需要將綁定數據集中每一行不斷重複的 HTML 內容放在 ItemTemplate 裏。
ListView 中的新功能,也是它與其它控件的真正不同之處在於引進了 LayoutTemplate。在 LayoutTemplate 中,您可以將要輸出的頂級 HTML 定義爲控件呈現的內容。例如,如果希望 ListView 作爲表格呈現,則可以在 LayoutTemplate 中包含頂級 <table> 和 <thead> 元素,把行和單元格的呈現留給 ItemTemplate,如圖 1 所示(在本示例中,綁定的數據源將顯示包含電影標題和發行日期的簡單表格)。圖 2 顯示了瀏覽器呈現。
<asp:ListView runat="server" ID="_simpleTableListView" 
  DataSourceID="_moviesDataSource">
  <LayoutTemplate>
    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>Title</th>
          <th>Release Date</th>
        </tr>
      </thead>
      <tbody>
        <asp:PlaceHolder runat="server" ID="itemPlaceholder" />
      </tbody>
    </table>
  </LayoutTemplate>
  <ItemTemplate>
    <tr>
      <td><%# Eval("movie_id") %></td>
      <td><%# Eval("title") %></td>
      <td><%# Eval("release_date", "{0:d}") %></td>
    </tr>
  </ItemTemplate>
</asp:ListView>

Figure 2 顯示在表格中的列表 (單擊該圖像獲得較大視圖)
LayoutTemplate 和 ItemTemplate 之間的關聯由 LayoutTemplate 中 ID 設置爲 itemPlaceholder 的單一服務器端控件完成。(您可以使用 ListView 的 ItemPlaceholderID 屬性更改 ID 字符串的默認值。)在第一個示例中,我將 PlaceHolder 控件的實例放置在模板中,即我希望注入 ItemTemplate 內容的位置。請注意:儘管必須支持子控件,但並沒有限制必須使用什麼類型的控件作爲佔位符——ID 纔是重要。例如,我可以使用服務器端表格行代替 PlaceHolder 控件編寫 LayoutTemplate,實現同樣的效果:
<LayoutTemplate>
  <table>
    <thead>
      <tr>
        <th>ID</th>
        <th>Title</th>
        <th>Release Date</th>
      </tr>
    </thead>
    <tbody>
      <tr runat="server" ID="itemPlaceholder" />
    </tbody>
  </table>
</LayoutTemplate>
通常情況下,出於以下兩個原因,我更喜歡使用通用的 PlaceHolder 控件。第一個原因是名稱匹配得很好。而且,該控件並不呈現其自身的 HTML,而是用 ItemTemplate 的內容代替,因此如果控件除在層次結構中保留位置以外無任何其它目的,這是更合乎邏輯的選擇。
當然,使 ListView 如此靈活的原因是您可以完全控制 LayoutTemplate 的內容。您不是隻能使用表格——您可以將任何希望呈現的 HTML 放置在 LayoutTemplate 中,只要注入 itemPlaceholder 控件位置時 ItemTemplate 的內容有效即可。以下是綁定到相同電影數據源的 ListView 示例,但這次不是表格,是帶有標題和發行日期的電影顯示在項目符號列表中(結果列表如圖 3 所示):
Figure 3 相同列表,不同格式 (單擊該圖像獲得較大視圖)
   <asp:ListView runat="server"
     ID="_simpleTableListView" 
     DataSourceID="_moviesDataSource">
     <LayoutTemplate>
       <ul>
         <asp:PlaceHolder runat="server" 
              ID="itemPlaceholder" />
       </ul>
     </LayoutTemplate>
     <ItemTemplate>
       <li><%# Eval("title") %>, 
           <%# Eval("release_date", "{0:d}") %> </li>
     </ItemTemplate>
                         </asp:ListView>

 

ListView 和 CSS
ASP.NET 開發人員長久以來在創建 CSS 驅動的站點時都受到單獨控件的限制。許多默認控件呈現內聯樣式,或者難於使 CSS 類與其 HTML 輸出部分相關聯。實際上 Microsoft 在 2006 年 4 月已發佈名爲“CSS 控件適配器”的工具包,該工具包爲幾個完全由 CSS 驅動的控件(包括 GridView)提供了可選呈現機制,幫助糾正該問題(有關詳細信息,請參見 2006 年 10 月的“非常 ASP.NET”專欄msdn.microsoft.com/msdnmag/issues/06/10/ExtremeASPNET)。這些備用呈現機制從未併入完整版當中,所以需要單獨安裝且缺少設計人員支持。
ListView 通過讓您完全控制何時何地應用樣式表,使您在站點裏利用 CSS 變得更爲簡捷。一種常見的情形是開發人員爲特定頁面手動預先設計,通常包含 HTML 和 CSS。採用傳統的 GridView 呈現數據表的特定設計總是很難保證正確,因爲 GridView 類僅提供用於修改 HTML 結果的有限掛接集。
我見過許多開發人員經歷過的試驗和錯誤,將樣式屬性應用到網格,查看頁面源以準確理解樣式放置的位置,並反覆試驗直到網格能夠按要求呈現爲止。使用 ListView,您不必再做這些猜測工作了,因爲現在您可以控制佈局和內容。
例如,假設提供給您的表格需要按照圖 4 所示的方式顯示,並使用由 .htm 和 .css 文件組成的設計,如圖 5中所示。


HTML
<div class="PrettyGrid">
  <table cellpadding="0" cellspacing="0" summary="">
    <thead>
      <tr>
        <th scope="col"><a href="http://.">ID</a></th>
        <th scope="col"><a href="http://.">Title</a></th>
        <th scope="col"><a href="http://.">Release date</a></th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>1</td>
        <td>Where the Wild Things Are</td>
        <td>12/15/2008</td>
      </tr>
  <!-- ... -->
    </tbody>
  </table>
  <div class="Pagination">
    <span>1</span>
    <a href="http://.">2</a>
    <a href="http://.">3</a>
  </div>
</div>
CSS
.PrettyGrid
{
  width: 100%;
}

.PrettyGrid div.Pagination,
.PrettyGrid div.Pagination a,
.PrettyGrid div.Pagination span
{
  color: #00FFFF;
  background: #284775;
  font-weight: normal;
  padding: 2px;
}
.PrettyGrid table
{
  border: solid 1px #CCCCCC;
  width: 100%;
}
/*...*/
Figure 4 表格目標設計 (單擊該圖像獲得較大視圖)
您可以通過從 HTML 中選取適當部分,並將其置於的對應模板中,來快速創建能夠精確按照 HTML/CSS 組合要求呈現的 ListView,如圖 6 所示。最終結果將與完全使用 CSS 設定 HTML 樣式時完全一致。僅更新 HTML 或相應的 CSS 就可以很容易地修改設計。
<asp:ListView ID="_moviesGrid" runat="server" DataKeyNames="movie_id" 
  DataSourceID="_moviesDataSource">            
  <LayoutTemplate>
    <div class="PrettyGrid">
      <table cellpadding="0" cellspacing="0" summary="">
        <thead>
          <tr>
            <th scope="col"><a href="http://.">ID</a ></th>
            <th scope="col"><a href="http://.">Title</a></th>
            <th scope="col"><a href="http://.">Release date</a></th>
          </tr>
        </thead>
        <tbody>
          <asp:PlaceHolder ID="itemPlaceholder" runat="server" />  
        </tbody>
      </table>
      <div class="Pagination">
        <span>1</span>
        <a href="http://.">2</a>
        <a href="http://.">3</a>
      </div>
    </div>
  </LayoutTemplate>

  <AlternatingItemTemplate>
    <tr class="Alternate">
      <td><asp:Label ID="movie_idLabel" runat="server" 
        Text='<%# Eval("movie_id") %>' /></td>
      <td><asp:Label ID="titleLabel" runat="server" 
        Text='<%# Eval("title") %>' /></td>
      <td><asp:Label ID="release_dateLabel" runat="server" 
        Text='<%# Eval("release_date", "{0:d}") %>' />  </td>
    </tr>
  </AlternatingItemTemplate>  

  <ItemTemplate>
    <tr>
      <td><asp:Label ID="movie_idLabel" runat="server" 
        Text='<%# Eval("movie_id") %>' /></td>
      <td><asp:Label ID="titleLabel" runat="server" 
        Text='<%# Eval("title") %>' /></td>
      <td><asp:Label ID="release_dateLabel" runat="server" 
        Text='<%# Eval("release_date", "{0:d}") %>' /> </td>
    </tr>
  </ItemTemplate>
</asp:ListView>

 

分頁
在前一部分開始時介紹的原 HTML 設計中內含分頁和排序,所以根據規範完整實現該網格的任務尚未完成。我們先分頁,然後再排序。
ListView 控件中的分頁通過引入另一個新控件 DataPager 實現。通過在單獨的控件中隔離分頁,DataPager 將分頁 UI 與 ListView 用於呈現數據的頁面分離。這意味着您可以在頁面的任何位置放置分頁 UI,並且可以創建任意多個 DataPager 控件。分頁控件一個常見的應用是在數據網格的頂部和底部提供分頁界面,這樣用戶不必滾動網格即可導航到下一頁——DataPager 可以很容易做到這一點。
我們先在上一節的 ListView 示例中實現分頁。要創建與 ListView 關聯的 DataPager 控件,最簡單方法是將 DataPager 控件實際嵌入到 ListView 的 LayoutTemplate 中:
<asp:ListView ID="_moviesGrid"
  runat="server" DataKeyNames="movie_id" 
  DataSourceID="_moviesDataSource">            
  <LayoutTemplate>
    <!-- ... -->
    <div class="Pagination">
      <asp:DataPager ID="_moviesGridDataPager" runat="server">
        <Fields>
          <asp:NumericPagerField />
        </Fields>
      </asp:DataPager>
    </div>
  </LayoutTemplate>
</asp:ListView>
通過將 DataPager 嵌入 ListView 的 LayoutTemplate 中,它們會建立內在聯繫。另一種方法是將 DataPager 放在頁面的其它位置,並通過將其 PagedControlID 設置爲關聯 ListView 的 ID 以便與 ListView 關聯。
在這種特例中,NumericPagerField 精確顯示了我想要的界面——就是一系列顯示爲超鏈接的數字,可以導航至頁面。DataPager 支持三種類型的字段:
  • NumericPagerField 顯示 1 2 3... 分頁界面。
  • NextPreviousPagerField 顯示“Next”(下一頁)、“Previous”(上一頁)、“First”(第一頁)和“Last”(最後一頁)按鈕在行間往復。
  • TemplatePagerField 讓您使用 PagerTemplate 定義精確設計和實現分頁接口的功能。
一般情況下,採用 DataPager 控件是爲任何實現了 IPageableItemContainer 界面的控件(目前 ListView 是唯一實現了該接口的控件)提供分頁支持,如下所示:
public interface IPageableItemContainer
{
    event EventHandler<PageEventArgs> TotalRowCountAvailable;
    void SetPageProperties(int startRowIndex, int maximumRows, 
                           bool databind);
    int MaximumRows { get; }
    int StartRowIndex { get; }
}
圖 7 顯示了 ListView、DataPager 與關聯的 DataSource 控件之間的關係。DataPager 從不與用於填充 ListView 的 DataSource 直接交互,而是通過該界面查詢所需的數據。
Figure 7 ListView、DataPager 和 DataSource 之間的關係 (單擊該圖像獲得較大視圖)
準備分頁時,首先是 ListView 查詢 DataSource 以查看其是否支持分頁,如果支持,那它是否能夠返回總行數。如果能夠返回總行數,ListView 將檢索數據源中的總行數,然後引發 TotalRowCountAvailable 事件,該事件作爲其 IPageableItemContainer 接口一部分實現。任何關聯的 DataPager 控件都將訂閱該事件,並使用總行數初始化顯示分頁界面所需的字段。DataPager 將隨後調用 ListView 的 SetPageProperties 方法設置初始行索引和要返回的最大行數。
當 ListView 從關聯的數據源檢索數據時,它將根據 DataPager 設置的值只請求行的子集。無論何時 DataPager 更改其當前頁索引(通常由於用戶交互),它都將再次調用 ListView 的 SetPageProperties 以反映當前需要檢索行的子集。可以通過設置 DataPager 控件的 PageSize 屬性來更改一個頁面上顯示的記錄條數,該屬性的值將影響相關 ListView 中設置的最大行數信息。
DataPager 還支持 QueryStringField 屬性,該屬性可以徹底更改 DataPager 的工作方式。通過將 QueryStringField 屬性設置爲某些字符串(例如 pageNum),表示您請求 DataPager 發送 HTTP GET 請求以響應用戶單擊頁面編號的操作,所請求的頁面編號將通過您指定字符串的查詢字符串參數發送,而不是通過傳統的 POST 回發模式發送。
該變化帶來的另一個好處是:它讓客戶端能夠創建到數據綁定 ListView 控件中特定頁面的書籤,因爲可以在 URL 中看到頁面編號。請注意,如果切換到這種 GET 通信模式,那由 ASP.NET AJAX UpdatePanel 控件使用的 POST 回發掛接機制將無法截取分頁請求,並會將其變爲異步回發:
<asp:DataPager ID="_moviesGridDataPager" runat="server"
  QueryStringField="pageNum" >
  <Fields>
    <asp:NumericPagerField />
  </Fields>
</asp:DataPager>
請注意:因爲 DataPager 完全依賴 ListView 執行實際的數據分頁,而 ListView 又依賴 DataSource 控件,所以對於其它數據綁定控件也存在相同的分頁限制。例如,對於 SqlDataSource 控件,僅當其設置爲 DataSet 模式時分頁才能正常工作,這意味着需要將整個結果集加載到內存中才能執行分頁。當然,您可以使用自定義 DataSource 控件或使用 ObjectDataSource 控件自定義自己的分頁。

 

排序、編輯、插入和刪除
如果 ListView 不具備支持排序和完備的創建、讀取、更新和刪除 (CRUD) 操作,那麼它是不完整的。它實現每種命令的方式與 FormView 控件實現命令的方式相似。
因爲 ListView 完全由模板驅動,所以對於其模板中將 CommandName 屬性設置爲以下七種特定命令字符串之一的按鈕,能夠予以識別:Cancel(取消)、Delete(刪除)、Select(選擇)、Edit(編輯)、Insert(插入)、Update(更新)和 Sort(排序)。每個命令都會啓動 ListView 中的相應操作——這樣如果希望爲 ListView 添加排序,那隻需要在 LayoutTemplate 中放置一個按鈕(圖 8 的示例中使用 LinkButton),將其 CommandName 屬性設置爲 Sort,並將 CommandArgument 設置爲希望數據源進行排序的列名稱。在圖 8 中,我將以前網格中每列的靜態標題鏈接修改爲可單擊的鏈接,通過單擊該鏈接可以請求 ListView 根據該列對數據進行排序。
<asp:ListView ID="_moviesGrid" runat="server" DataKeyNames="movie_id" 
  DataSourceID="_moviesDataSource">            
  <LayoutTemplate>
    <div class="PrettyGrid">
      <table cellpadding="0" cellspacing="0" summary="">
        <thead>
          <tr>
            <th scope="col">
              <asp:LinkButton ID="_movieIdSortLink" 
                CommandName="Sort" CommandArgument="movie_id" 
                runat="server">ID</asp:LinkButton>
            </th>
            <th scope="col">
              <asp:LinkButton ID="_titleSortLink" 
                CommandName="Sort" CommandArgument="title" 
                runat="server">Title</asp:LinkButton>
            </th>
            <th scope="col">
              <asp:LinkButton ID="_releaseDateSortLink"
                CommandName="Sort" CommandArgument="release_date" 
                runat="server">Release date</asp:LinkButton>
            </th>
          </tr>
        </thead>  
    <!-- ... -->
  </LayoutTemplate>
</asp:ListView>

您可以爲啓動編輯模式、刪除行或在數據集中插入新行添加命令按鈕,詳細過程與其它基於模板的數據綁定控件(如 FormView 和 GridView)基本相同,此處就不再贅述。

 

分組
ListView 的最後一個主要功能是將數據分組成子集的能力,非常類似於 DataList 控件提供的功能。DataList 是表格格式的控件,它可以在所呈現數據表的每個單元格中呈現單行數據。您可以通過設置 RepeatColumns 屬性來控制將基礎數據集的多少行歸入單個表格行中。
由於 ListView 並不僅限於呈現表格,所以它需要更加一般的方式指定將組合呈現的項目組,而這正是 GroupTemplate 提供的方式。圖 9 顯示了 ListView 中 LayoutTemplate、GroupTemplate 和 ItemTemplate 元素之間的關係。GroupTemplate 可以爲基礎數據集中每 n 個元素指定外圍 HTML,其中 n 的值由 ListView 的 GroupItemCount 屬性指定。
Figure 9 ListView 中的模板 (單擊該圖像獲得較大視圖)
當在 ListView 中使用 GroupTemplate 時,不需要再在 LayoutTemplate 中指定帶有 itemPlaceholder ID 的控件——該控件現在需要位於 GroupTemplate 之內。而是需要在 LayoutTemplate 中指定帶有 groupPlaceholder ID 的控件(可以通過設置 ListView 的 GroupPlaceholderID 屬性更改控件 ID)以說明對於基礎數據集中每 n 個項目,應在哪個位置注入 GroupTemplate 的內容。
例如,圖 10 中的 ListView 顯示瞭如何通過將 GroupTemplate 定義爲搜索行,並將 ItemTemplate 設爲僅佈局單元格,以在表格的每一行中顯示來自數據庫的四個電影。結果如圖 11 所示。
<asp:ListView ID="_groupListView" runat="server" 
  DataKeyNames="movie_id" DataSourceID="_moviesDataSource" 
  GroupItemCount="4" >
  <GroupTemplate>
    <tr>
      <asp:PlaceHolder runat="server" ID="itemPlaceholder" />
    </tr>
  </GroupTemplate>
  <LayoutTemplate>
    <table>
      <asp:PlaceHolder ID="groupPlaceholder" runat="server" />
    </table>
  </LayoutTemplate>
  <ItemTemplate>
    <td>
      movie_id:
      <asp:Label ID="_movie_idLabel" runat="server" 
        Text='<%# Eval("movie_id") %>' /> <br />
      title:
      <asp:Label ID="_titleLabel" runat="server" 
        Text='<%# Eval("title") %>' /> <br />
      release_date:
      <asp:Label ID="_release_dateLabel" runat="server" 
        Text='<%# Eval("release_date", "{0:d}") %>' /> <br />
      <br />
    </td>
  </ItemTemplate>
</asp:ListView>

Figure 11 結果 Web 頁面中的 GroupTemplate 行 (單擊該圖像獲得較大視圖)
這與使用 DataList 完成的工作非常相似,但因爲使用的是 ListView,所以可以像前面所示的網格呈現一樣輕鬆添加分頁和排序功能,而使用 DataList 完成這些工作則非常複雜。用於本文的下載代碼包含實現了分頁和排序功能的示例供您參考。

 

開始執行 ListView
您可能希望通過使用 Visual Studio 2008 中的設計器來試用 ListView 控件,該設計器可以提供五種不同的佈局供您選擇:網格、平鋪、項目符號列表、流動和單行。您可以快速查看可用的各種佈局選項——但 ListView 真正強大的功能在於您對它所呈現 HTML 的控制,所以在實際的項目中您很可能要自行構建 LayoutTemplate。您是否最後決定今後每次遇到數據綁定都使用 ListView 呢?雖然可能有點過頭——但知道您會這樣做我還是很高興。我想今後我還會更多地研究這個靈活的數據綁定控件。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章