當前位置:開發者網絡 >> 技術教程 >> ASP教程 >> 數據庫相關 >> 內容
精彩推薦
分類最新教程
分類熱點教程
    
使用 ASP+ DataGrid 控件來創建主視圖/詳細資料視圖
作者:未知
日期:2005-03-30
人氣:
投稿:snow(轉貼)
來源:未知
字體:
收藏:加入瀏覽器收藏
以下正文:
簡介

Microsoft® Visual Studio.NET 的下一發行版包括 DataGrid Web 控件 (作為服務器控件的 Active Server Page+ (ASP+) 套件的一部分)。 該控件提供用以根據數據源的內容來表示 HTML 的功能。

DataGrid 控件可以用於若干個只讀匯報情形。該控件設計用於對豐富而完全可定制的數據表格佈局的輸出進行簡化。還提供多個機制,用於通過超級鏈接及其對選擇、排序、分頁和原地編輯和其它特性的支持,為輸出添加交互性。這使得該控件在若干的常見 Web 應用方案中很有用,諸如列表、購物車和查詢結果。

DataGrid 還提供一些功能,這些功能具有 ASP+ 架構所特有的所有服務器控件的特點。該控件包含進行與瀏覽器無關的輸出所需的邏輯,同時提供了一個統一的編程模型,從而能夠處理回傳數據,以及對請求之間的狀態進行管理。這樣,開發商就可以針對帶有屬性、方法和事件的對象模型進行編程,而不必處理直接用 HTML 編程所帶來的不一致性和複雜性。

使用 ASP+ 列表綁定控件 (英文) 介紹 DataGrid 控件以及相關的 DataList 和 Repeater 控件。還介紹了數據綁定、模板和格式化等等多個關鍵的概念。該文以此為基礎寫成,並將重點放在 DataGrid 控件,以揭示如何在您自己的應用程序中利用該控件所提供的功能。


--------------------------------------------------------------------------------


我們要建立什麼?

該文舉出了一序列的示例頁面,彼此結合,從而最終生成一個頁面,該頁面以示例數據庫的 Authors 表和 Titles 表為依據,提供主/詳細資料視圖(該數據庫隨 Microsoft SQL Server™2000 一起發運)。序列中的每個頁面均介紹 DataGrid 控件的一個新的特性或功能。下列圖像是從 pubs 數據庫抽取出來的。

主/詳細資料視圖類似於 Microsoft Access 所介紹的窗體/子窗體概念。也類似於隨 Microsoft Visual InterDev®6.0 一起發運的 DataForm Wizard (數據窗體嚮導)。主/詳細資料視圖顯示一到多的關係結果,其中視圖的一個部分顯示第一個查詢或主查詢的結果。然後跟蹤一個選擇,以篩選所使用的第二個查詢的結果,從而在視圖的另一部分顯示選擇內容的詳細資料。



圖 1. 完成的頁面

圖 1 將 Author 列表顯示在頁面的上半部分,並將關於所選作者的詳細資料(包括相關書名)顯示在下半部分。 Authors 列表和 Titles 均是用 DataGrid 控件加以表示的。 顯示作者的 DataGrid 舉例說明如何進行選擇、排序、和分頁。顯示書名的 DataGrid 演示如何進行原地編輯、格式化和定制列。

數據訪問

為了使示例自成一體,從 SQL Server 抽取數據並將該數據連同其架構信息一同保留為一個 XML 文件 TitlesDB.xml。下面是該文件的一個片斷。

<root>
<schema id="DocumentElement" targetNamespace=""
xmlns="http://www.w3.org/1999/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<element name="Author">
<complexType content="elementOnly">
<element name="au_id" type="string" minOccurs="1"
maxOccurs="1"></element>
<element name="au_name" type="string" minOccurs="1"
maxOccurs="1"></element>
<element name="address" type="string" minOccurs="0"
maxOccurs="1"></element>
<element name="city" type="string" minOccurs="0"
maxOccurs="1"></element>
<element name="state" type="string" minOccurs="0"
maxOccurs="1"></element>
<element name="zip" type="string" minOccurs="0"
maxOccurs="1"></element>
<element name="phone" type="string" minOccurs="0"
maxOccurs="1"></element>
</complexType>
<unique name="AuthorConstraint" msdata:PrimaryKey="True">
<selector>.</selector>
<field>au_id</field>
</unique>
</element>

<element name="Title">
<complexType content="elementOnly">
<element name="title_id" type="string" minOccurs="1"
maxOccurs="1"></element>
<element name="au_id" type="string" minOccurs="1"
maxOccurs="1"></element>
<element name="title" type="string" minOccurs="1"
maxOccurs="1"></element>
<element name="price" msdata:DataType="System.Currency"
type="string"
minOccurs="1" maxOccurs="1"></element>
<element name="pubdate" type="timeInstant" minOccurs="1"
maxOccurs="1"></element>
</complexType>
<unique name="TitleConstraint" msdata:PrimaryKey="True">
<selector>.</selector>
<field>title_id</field>
</unique>
<key name="AuthorTitle">
<selector>../Author</selector>
<field>au_id</field>
</key>
<keyref refer="AuthorTitle">
<selector>.</selector>
<field>au_id</field>
</keyref>
</element>
</schema>
<DocumentElement>
<Author>
<au_id>154-00-1300</au_id>
<au_name>John Doe</au_name>
<phone>425 705 1234</phone>
<address>One Microsoft Way</address>
<city>Redmond</city>
<state>CA</state>
<zip>98005</zip>
</Author>

<Title>
<title_id>BU1032</title_id>
<au_id>213-46-8915</au_id>
<title>The Busy Executive's Database Guide</title>
<price>19.99</price>
<pubdate>1991-06-12T07:00:00</pubdate>
</Title>
</DocumentElement>
</root>

這些樣例簡化了數據訪問,從而將重點全部放在 DataGrid 的使用上。上面的 XML 被加載進一個 DataSet。 DataSet 為數據提供高速緩存,從而可以進行篩選、排序和編輯等等各種操作。下面的代碼來自 Global.asax,用於加載 DataSet 和將其保存為 Session 狀態。

public void Session_OnStart() {
// 將樣例中所用的數據載入會話範圍的 DataSet.

FileStream fs = null;
DataSet ds = null;

try {
fs = new FileStream(Server.MapPath("Data\\TitlesDB.xml"),
FileMode.Open, FileAccess.Read);
ds = new DataSet();
ds.ReadXml(fs);
} finally {
if (fs != null) {
fs.Close();
fs = null;
}
}
Session["AppData"] = ds;
}

在實際的 Web 應用程序中,通常不是使用處於 Session 或 Application 狀態的高速緩存數據,而是通過所存儲的過程、中間層業務對象,或通過調用 Web 服務所揭示的方法來訪問和修改數據。無論採取怎樣的手段來訪問數據,您會發現你依舊以同樣的方式來編程和與控件的對象模型進行進行交互。 www.IBuySpy.com (英文) 網站就是演示這些概念的一個很好的應用示例。


--------------------------------------------------------------------------------


第 1 步: 一個基本的 DataGrid

序列的第一步展示了一個頁面,其中包含單獨一個 DataGrid 控件,用於顯示來自數據源的一個只讀作者列表。結果類似於 使用 ASP+ 列表綁定控件 (英文) 所取得的效果。



圖 2. 完成第 1 步後的頁面

DataGrid 聲明來自:

Step1.aspx:

<asp:DataGrid id="authorsGrid" runat="server"
AutoGenerateColumns="false"
BackColor="White"
BorderWidth="1px" BorderStyle="Solid" BorderColor="Tan"
CellPadding="2" CellSpacing="0"
Font-Name="Verdana" Font-Size="8pt">

<property name="Columns">
<asp:BoundColumn HeaderText="ID" DataField="au_id">
<property name="HeaderStyle">
<asp:TableItemStyle Width="100px"/>
</property>
</asp:BoundColumn>
<asp:BoundColumn HeaderText="Name" DataField="au_name">
<property name="HeaderStyle">
<asp:TableItemStyle Width="150px"/>
</property>
</asp:BoundColumn>
<asp:BoundColumn HeaderText="State" DataField="state">
<property name="HeaderStyle">
<asp:TableItemStyle Width="50px"/>
</property>
</asp:BoundColumn>
</property>

<property name="HeaderStyle">
<asp:TableItemStyle BackColor="DarkRed" ForeColor="White"
Font-Bold="true"/>
</property>

<property name="ItemStyle">
<asp:TableItemStyle ForeColor="DarkSlateBlue"/>
</property>

<property name="AlternatingItemstyle">
<asp:TableItemStyle BackColor="Beige"/>
</property>

</asp:DataGrid>

上面的代碼展示 DataGrid,該控件的各種屬性已經過聲明設定。 DataGrid 控件與其它 Web 控件如 Font、BackColor、ForeColor 和 BorderWidth 共享一組公用的樣式屬性。另外, DataGrid 提供僅適用於表的屬性如 CellPadding。最後, DataGrid 提供附加的樣式屬性,這些樣式屬性影響其中各項目和列如 HeaderStyle、ItemStyle 和 AlternatingItemStyle 的表示。這些樣式屬性用於創建豐富多采且極富魅力的數據視覺效果。

DataGrid 支持從其所綁定的數據源自動生成列的功能。但是,在本例中, AutoGenerateColumns 屬性已被設定為 false。因此必須借助要展示的列集對 Columns 集合進行初始化。從而可以更多地控制表現效果,諸如列的次序和標頭以及與每列對應的樣式。這一步中所定義的列均為 BoundColumns,從而可以通過其 DataField 屬性,綁定到數據源的單獨一個字段。您在以後步驟中可以看到, DataGrid 允許選擇各種各樣類型的列。

下面的類包含支持本頁面的代碼。

Step1Page.cs:

namespace Samples {
...

public class Step1Page : Page {

protected DataGrid authorsGrid;

// 檢索存入會話狀態的應用程序數據
private DataSet GetSessionData() {
return (DataSet)Session["AppData"];
}

// 檢索 Authors 表
private ICollection GetAuthors() {
DataSet ds = GetSessionData();
DataView dv = ds.Tables["Author"].DefaultView;

dv.RowFilter = String.Empty;
return dv;
}

// 將 Authors 表載入 DataGrid
private void LoadAuthorsGrid() {
ICollection authors = GetAuthors();

authorsGrid.DataSource = authors;
authorsGrid.DataBind();
}

// 超控 OnLoad,以在第一次請求過程中加載數據
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);

if (!IsPostBack) {
LoadAuthorsGrid();
}
}
}
}

該類超越 Page 的 OnLoad 方法 (類似於實施 Page_Load),將 Author 列表作為 DataGrid 數據源進行加載。與其它服務器控件一樣, DataGrid 實施顯式的數據綁定模型,其中控件只在 DataBind 方法被調用時才列舉器數據源中的值。這樣設計各個控件,您就可以完全控制在哪個時間點需要數據源,並將無需數據時的數據訪問降至最低,例如大多數的往返過程。這一點會在將來的步驟中得到證明。

代碼還展示從 Session 狀態檢索的數據,數據是在會話啟動過程中存為該狀態的。


--------------------------------------------------------------------------------


第 2 步: 帶有多頁面的主/詳細資料視圖

創建主/詳細資料視圖的一個方法就是使用多頁面。在該方法中,主查詢中的選定值的詳細資料視圖被顯示在次要頁面上。在關於選定內容的信息中,該次要頁面作為 URL 請求中的一個參數得到傳遞。



圖 3. 第 2 後的頁面,展示詳細資料頁面的浮動視圖

Step2.aspx 包含對 DataGrid 的更改,以使其包含一個名為 DataGrid 聲明的列。

Step2.aspx:

<asp:DataGrid id="authorsGrid" runat="server"
AutoGenerateColumns="false"
BackColor="White"
BorderWidth="1px" BorderStyle="Solid" BorderColor="Tan"
CellPadding="2" CellSpacing="0"
Font-Name="Verdana" Font-Size="8pt">

<property name="Columns">
<asp:BoundColumn HeaderText="ID" DataField="au_id">
<property name="HeaderStyle">
<asp:TableItemStyle Width="100px"/>
</property>
</asp:BoundColumn>
<asp:BoundColumn HeaderText="Name" DataField="au_name">
<property name="HeaderStyle">
<asp:TableItemStyle Width="150px"/>
</property>
</asp:BoundColumn>
<asp:BoundColumn HeaderText="State" DataField="state">
<property name="HeaderStyle">
<asp:TableItemStyle Width="50px"/>
</property>
</asp:BoundColumn>
<asp:HyperLinkColumn Text="Details" DataNavigateUrlField="au_id"
DataNavigateUrlFormatString="Step2a.aspx?AuthorID={0}"/>
</property>

<property name="HeaderStyle">
<asp:TableItemStyle BackColor="DarkRed" ForeColor="White"
Font-Bold="true"/>
</property>

<property name="ItemStyle">
<asp:TableItemStyle ForeColor="DarkSlateBlue"/>
</property>

<property name="AlternatingItemstyle">
<asp:TableItemStyle BackColor="Beige"/>
</property>

</asp:DataGrid>

DataGrid 聲明與第 1 步中的 DataGrid 聲明幾乎一樣。已將單獨一個 HyperLinkColumn 添加到 Columns 集合。 HyperLinkColumn 用來在 DataGrid 的每行中創建一個可導航的鏈接。該類型的列允許其 Text 和 NavigateUrl 屬性與數據綁定。這樣, Text 屬性是靜態的,而 NavigateUrl 是數據綁定到作者 ID 的(通過設定 DataNavigateUrl 屬性)。另外,指定 DataNavigateUrlFormatString 建立一個以 Author ID 為參數的指向詳細資料頁面的 URL。 因此,每行均包含一個帶有「詳細資料」超級鏈接的附加列,而該鏈接的 URL 以與該行關聯的數據為依據。

HyperLinkColumn 代表著向本來只讀的數據顯示添加交互功能的第一步。

支持該頁面 (Step2Page.cs) 的代碼與第 1 步相同。添加這一列並不添加任何代碼,也不導致任何代碼發生變化,因此此處沒有列出那些代碼。

Step2a.aspx 實施詳細資料頁面,以顯示某一具體作者的詳細資料。

Step2a.aspx:

<asp:Panel id="detailsPanel" runat="server">
<table border="0" cellspacing="0" cellpadding="2" width="100%"
style="font-family: verdana; font-size: 8pt">
<tr>
<td width="200"><b>Name:</b></td>
<td width="100%">
<%# DataBinder.Eval(CurrentAuthor, "au_name") %>
</td>
</tr>
<tr>
<td width="200"><b>ID:</b></td>
<td width="100%">
<%# DataBinder.Eval(CurrentAuthor, "au_id") %>
</td>
</tr>
<tr>
<td width="200" valign="top"><b>Address:</b></td>
<td width="100%">
<%# DataBinder.Eval(CurrentAuthor, "address") %><br>
<%# DataBinder.Eval(CurrentAuthor, "city") %>,
<%# DataBinder.Eval(CurrentAuthor, "state") %>
<%# DataBinder.Eval(CurrentAuthor, "zip") %>
</td>
</tr>
<tr>
<td width="200"><b>Phone:<b></td>
<td width="100%">
<%# DataBinder.Eval(CurrentAuthor, "phone") %>
</td>
</tr>
<tr>
<td colspan="2"><b>Title(s) Authored</b></td>
</tr>
<tr>
<td colspan="2">
<asp:DataGrid id="titlesGrid" runat="server"
DataSource='<%# DataBinder.Eval(CurrentAuthor, "AuthorTitle") %>'
AutoGenerateColumns="false"
ShowFooter="true"
BackColor="White"
BorderWidth="1px" BorderStyle="Solid" BorderColor="Tan"
CellPadding="2" CellSpacing="0"
Font-Name="Verdana" Font-Size="8pt"
OnItemCreated="OnItemCreatedTitlesGrid">

<property name="Columns">
<asp:BoundColumn HeaderText="ID" DataField="title_id">
<property name="HeaderStyle">
<asp:TableItemStyle Width="100px"/>
</property>
</asp:BoundColumn>
<asp:BoundColumn HeaderText="Title" DataField="title">
<property name="HeaderStyle">
<asp:TableItemStyle Width="250px"/>
</property>
</asp:BoundColumn>
<asp:BoundColumn HeaderText="Published" DataField="pubdate"
DataFormatString="{0:MMM yyyy}">
<property name="HeaderStyle">
<asp:TableItemStyle Width="100px"/>
</property>
</asp:BoundColumn>
<asp:BoundColumn HeaderText="Price" DataField="price"
DataFormatString="{0:c}">
<property name="HeaderStyle">
<asp:TableItemStyle Width="50px"/>
</property>
<property name="ItemStyle">
<asp:TableItemStyle HorizontalAlign="Right"/>
</property>
</asp:BoundColumn>
</property>

<property name="HeaderStyle">
<asp:TableItemStyle BackColor="DarkRed" ForeColor="White"
Font-Bold="true"/>
</property>

<property name="FooterStyle">
<asp:TableItemStyle BackColor="Tan"/>
</property>

<property name="ItemStyle">
<asp:TableItemStyle ForeColor="DarkSlateBlue"/>
</property>

<property name="AlternatingItemstyle">
<asp:TableItemStyle BackColor="Beige"/>
</property>

</asp:DataGrid>
</td>
</tr>
</table>
</asp:Panel>

本頁包含若干使用 DataBinder.Eval 的數據綁定表達式。這些表達式抽取本頁代碼中所實施的 CurrentAuthor 屬性的各個屬性。

DataGrid 用於顯示選定作者所編著的書名。與第 1 步相同, DataGrid 包含一個針對要顯示的列的定義,以及用於為列、行和總體控制提供可視格式化的樣式屬性設置。

BoundColumns 還允許對數據進行格式化。正如在上面聲明中看到的那樣, DataFormatString 屬性用於對日期和貨幣值進行格式化。格式化對於表示本地化文字和控制非字符串類型的文字呈現來講極其有用。

Step2aPage.cs 包含支持詳細資料頁面的代碼。

Step2aPage.cs:

namespace Samples {
...

public class Step2aPage : Page {
private object currentAuthor;

// 返回當前選定的 Author
public object CurrentAuthor {
get {
return currentAuthor;
}
}

// 檢索存入會話狀態的應用程序數據
private DataSet GetSessionData() {
return (DataSet)Session["AppData"];
}

// 處理 ItemCreated 事件,以將標尾定制為
// 顯示總結信息
protected void OnItemCreatedTitlesGrid(object sender,
DataGridItemCreatedEventArgs e) {
if (e.Item.ItemType == ListItemType.Footer) {
int cellCount = e.Item.Cells.Count;

for (int i = 0; i < cellCount - 1; i++) {
e.Item.Cells.RemoveAt(0);
}

int itemCount = titlesGrid.Items.Count;
string itemCountString;
if (itemCount == 0) {
itemCountString = "No Titles Found";
}
else {
itemCountString = Int32.ToString(itemCount) +
" title(s)";
}

TableCell summaryCell = e.Item.Cells[0];

summaryCell.Text = itemCountString;
summaryCell.ColumnSpan = cellCount;
summaryCell.HorizontalAlign = HorizontalAlign.Right;
}
}

// 超控 OnLoad,以載入選定作者的詳細資料
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);

string authorID = Request.QueryString["AuthorID"];
if (authorID != null) {
SelectAuthor(authorID);
detailsPanel.DataBind();
}
}

// 根據給定作者 ID 來設置 CurrentAuthor 對像
private void SelectAuthor(string authorID) {
DataSet ds = GetSessionData();
DataView dv = ds.Tables["Author"].DefaultView;

dv.RowFilter = "au_id = '" + authorID + "'";
currentAuthor = dv[0];
}
}
}

通過訪問 Request.QueryString 集合,類就超越頁面的 OnLoad 方法來檢索作為 URL 請求中的參數傳來的 Author ID。然後使用該 Author ID 來查詢數據源和設置 CurrentAuthor 屬性。最後,調用 DataBind,從而為所有的數據綁定的表達式求值。

另外,該頁面為 DataGrid 控件的 ItemCreated 事件實施了一個事件處理器。 ItemCreated 事件是 DataGrid 為其高級用途提供的擴展機制之一。該事件允許從行的控件結構內部添加和刪除控件,以及在特殊情況下將其添加到特定行。

DataGrid 每次創建一個項目(或行)時,就引發該事件。這具體有兩種情況:

要對控件進行數據綁定,且項目需要從頭創建,則在將項目進行數據綁定之前,引發該事件。


當要從往返過程中的保存狀態創建項目時,則在將所保存的狀態載入項目及其包含的控件之前引發該事件。
結果是,該事件提供一個掛鉤,用於對項目的現有控件結構進行更改。

在本例中,處理器修改控件的標尾,以顯示所列書名的的一個計數。標尾所包含的列的數目與其它行一樣。摘要需要橫跨整個 DataGrid。因此,處理器僅保留行中的一個單元格,將其餘全部刪除,並將僅剩的單元格的 ColumnSpan 重置,以使其橫跨整個列集,設定其 HorizontalAlign 屬性,以使文字右對齊,最後設定其 Text,指示計數。

處理該事件時,只有一條規則需要遵守:您必須進行同樣的結構轉換,無論調用該項目的上下文如何,無論是在數據綁定過程中,還是在往返過程中。


--------------------------------------------------------------------------------


第 3 步: 單頁面中的主/詳細資料視圖

創建主/詳細資料視圖的另一備選且更常用的方法就是用單頁面顯示這些視圖。



圖 4. 完成第 3 步後的頁面

Authors DataGrid 來自:

Step3.aspx:

<asp:DataGrid id="authorsGrid" runat="server"
...
DataKeyField="au_id"
OnSelectedIndexChanged="OnSelIndexChangedAuthorsGrid">

<property name="Columns">
<asp:ButtonColumn Text="Select" Command="Select"/>
...
</property>

...

<property name="SelectedItemStyle">
<asp:TableItemStyle BackColor="PaleGoldenRod" Font-Bold="true"/>
</property>
</asp:DataGrid>

與前一步相比,該聲明中有三處變化。

首先,在第 2 步中添加的 HyperLinkColumn 已被刪除。這不再需要,因為整個視圖是在單頁面中實施的。

其次,向列集添加了一個新的列類型 ButtonColumn。該列在每行中生成 LinkButton,用於提交該頁,而不是從該頁進行瀏覽。列的 Command 屬性設定為 Select,對相應的 LinkButton 屬性進行設定。 DataGrid 將 Select 作為一個標準命令,將包含被單擊按鈕的列選定。

當選定內容發生變化時, DataGrid 就引發 SelectedIndexChanged 事件,該事件在代碼中得到處理。 DataKeyField 屬性頁得到設定,從而導致 DataKeys 集合填置與數據源中的每個項目相對應的值。

該頁面還包含針對題為 detailsPanel 的面板內的詳細資料節的 UI 和佈局。這是從第 2 步原樣複製的。

Step3Page.cs 表示這一步中的 .aspx 頁面的支持代碼。其中包括來自第 2 步中兩個有代碼支持的文件的代碼組合。來自詳細資料頁面的大部分代碼均為原樣照搬。下面顯示的代碼包含我們所作的更改和補充。

Step3Page.cs:

namespace Samples {
...

public class Step3Page : Page {
private object currentAuthor;

// 將 Authors 表載入 DataGrid
// 另外還更新選定的作者
private void LoadAuthorsGrid() {
ICollection authors = GetAuthors();

authorsGrid.DataSource = authors;
if (authors.Count != 0) {
authorsGrid.SelectedIndex = 0;
}
else {
authorsGrid.SelectedIndex = -1;
}

authorsGrid.DataBind();
UpdateDetails();
}

// 處理作者網格中的 SelectedIndexChanged 事件,以
// 更新詳細資料
protected void OnSelIndexChangedAuthorsGrid(object sender,
EventArgs e) {
UpdateDetails();
}

// 根據當前選定的作者來更新
// 詳細資料節
private void UpdateDetails() {
UpdateSelection();

if (currentAuthor != null) {
detailsPanel.Visible = true;
detailsPanel.DataBind();
}
else {
detailsPanel.Visible = false;
}
}

// 更新當前選定的作者
private void UpdateSelection() {
int selectedIndex = authorsGrid.SelectedIndex;

currentAuthor = null;
if (selectedIndex != -1) {
string authorID =
(string)authorsGrid.DataKeys[selectedIndex];

DataSet ds = GetSessionData();
DataView dv = ds.Tables["Author"].DefaultView;

dv.RowFilter = "au_id = '" + authorID + "'";
currentAuthor = dv[0];
}
}
}
}

每次加載 Authors DataGrid 時,就初始化其 SelectedIndex 屬性。一旦得到綁定,即其 DataKeys 集合填置完畢,就通過調用 UpdateDetails,更新詳細資料節。

針對 SelectedIndexChanged 事件的處理器中的詳細資料節也得到更新。注意,此時已借助 DataBind 未被調用以來的保存狀態將 DataKeys 集合填置完畢。

UpdateDetails 方法首先調用 UpdateSelection。 UpdateSelection 使用 Authors DataGrid 的 SelectedIndex 和 DataKeys 屬性來確定選定作者的 ID 和初始化 CurrentAuthor 屬性。然後, UpdateDetails 調用 detailsPanel 控件上的 DataBind,對訪問 CurrentAuthor 的數據綁定表達式進行求值。

除了借助 SelectedIndexChanged 事件進行選擇跟蹤,還可以從本樣例實現另一關鍵概念。注意,改變選擇內容並不需要已將 Authors DataGrid 進行過數據綁定。因此,從不需要重新加載 Authors 列表,從而極大地減少了對 Authors 表的訪問。這是 ASP+ 中所實施的顯式數據綁定模型的一個關鍵益處。


--------------------------------------------------------------------------------


第 4 步: 排序

DataGrid 支持生成可點擊標頭的功能,此類標頭可以用於讓最終用戶對控件中所展示的數據進行排序。這一步添加了對 Authors 列表進行排序的功能。



圖 5. 完成第 4 步後頁面的屏幕快照

Authors DataGrid 來自:

Step4.aspx

<asp:DataGrid id="authorsGrid" runat="server"
...
AllowSorting="true"
OnSortCommand="OnSortCommandAuthorsGrid"
OnItemCreated="OnItemCreatedAuthorsGrid">

<property name="Columns">
<asp:ButtonColumn Text="Select" Command="Select"/>
<asp:BoundColumn HeaderText="ID" DataField="au_id">
<property name="HeaderStyle">
<asp:TableItemStyle Width="100px"/>
</property>
</asp:BoundColumn>
<asp:BoundColumn HeaderText="Name" DataField="au_name"
SortField="au_name">
<property name="HeaderStyle">
<asp:TableItemStyle Width="150px"/>
</property>
</asp:BoundColumn>
<asp:BoundColumn HeaderText="State" DataField="state"
SortField="state">
<property name="HeaderStyle">
<asp:TableItemStyle Width="75px"/>
</property>
</asp:BoundColumn>
</property>

...
</asp:DataGrid>

通過將 AllowSorting 設定為 true,啟用排序。然後,對不支持排序的每列的 SortField 屬性進行設定。沒有設定該屬性的列不會生成可點擊標頭。最後,處理 SortCommand 事件,這會在有代碼支持的文件的上下文中加以論述。樣例還為 ItemCreated 事件添加了一個事件處理器,以在視覺上顯示列標頭中的當前排序設置。下面的代碼展示為向 Authors 列表添加排序功能而在有代碼支持的類中進行更改和補充。

Step4Page.cs:

namespace Samples {
...

public class Step4Page : Page {

// 返回當前的排序方向,該信息是在
// Page 狀態中維持的
protected bool SortAscending {
get {
object o = State["SortAscending"];
if (o != null)
return (bool)o;
return true;
}
set {
State["SortAscending"] = value;
}
}

// 返回當前的排序字段,該信息是在
// Page 狀態中維持的
protected string SortField {
get {
object o = State["SortField"];
if (o != null)
return (string)o;
return "au_name";
}
set {
State["SortField"] = value;
}
}

// 檢索 Authors 表
private ICollection GetAuthors() {
DataSet ds = GetSessionData();
DataView dv = ds.Tables["Author"].DefaultView;

dv.RowFilter = String.Empty;

string sort = SortField;
if (SortAscending == false) {
sort += " desc";
}
dv.Sort = sort;

return dv;
}

// 處理 ItemCreated 事件,以用排序圖符對標頭
// 進行定制
protected void OnItemCreatedAuthorsGrid(object sender,
DataGridItemCreatedEventArgs e) {
if (e.Item.ItemType == ListItemType.Header) {
string sortField = SortField;
bool ascending = SortAscending;

Label sortGlyph = new Label();
sortGlyph.Text = ascending ? " 5" : " 6";
sortGlyph.Font.Name = "Webdings";

TableCell cell = null;
if (sortField.Equals("au_name")) {
cell = e.Item.Cells[2];
}
else if (sortField.Equals("state")) {
cell = e.Item.Cells[3];
}

if (cell != null) {
cell.Controls.Add(sortGlyph);
}
}
}

// 處理作者網格中的 SortCommand 事件,以更新
// 排序參數和重新加載新排序的數據
protected void OnSortCommandAuthorsGrid(object sender,
DataGridSortCommandEventArgs e) {
string currentSortField = SortField;

SortField = e.SortField;
if (currentSortField.Equals(e.SortField)) {
SortAscending = !SortAscending;
}
else {
SortAscending = true;
}

LoadAuthorsGrid();
}
}
}

頁面將當前字段和排序方向作為名值對,保留在頁面的 State 屬性中,並將其作為 SortField 和 SortAscending 屬性提供出來,此時,頁面負責在往返過程之間維持這些屬性的值。

這些屬性用於 GetAuthors 函數,這裡,在返回 Author 列表 之前,會根據屬性的當前值對其進行排序。

用於 SortCommand 事件的事件處理器在 DataGridSortCommandEventArgs 的一個實例中得到傳遞。該對像包含 SortField 屬性的值,而該屬性與標題被單擊的列相關聯。您可以選擇對該值進行任意處理,只要該處理在您的應用程序中合理。例如,該值可以包含單個字段的名稱,例如本樣例中的情形,也可以包含排序信息,從而允許進行多列排序。

實施該方法,對 SortField 和 SortAscending 屬性的值進行更新。最後,該方法調用 LoadAuthorsGrid,對 Authors DataGrid 進行數據綁定。此時情況是, DataGrid 的列需要重新生成,要求您設定數據源和調用 DataBind。

ItemCreated 的事件處理器類似於第 2 步中用於 Titles DataGrid 的事件處理器。此時,處理器修改標頭行的控件結構,具體方法是添加表示上升和下降的圖符,指示當前已排序的列和當前的排序方向。

這裡有一個問題需要回答,DataGrid 為何不對其數據進行實際的排序。這主要有兩個原因。首先, ASP+ 的數據源是一般的 ICollection,以便您在選擇數據源時擁有最大的靈活性。數據源並不包含內置的排序語義。其次,也是更重要的一點, 在每次請求過程中,自動排序均會需要數據源的一個活動的實例。這不太適合用於顯式數據綁定結構中,因為這需要您在頁面的往返過程中訪問和加載數據。


--------------------------------------------------------------------------------


第 5 步: 分頁

DataGrid 提供顯示特殊行的功能,該行包含用於顯示頁碼和「下一步」/「上一步」瀏覽按鈕的 UI。這一步添加了對 Authors 列表進行分頁查看的功能。



圖 6. 完成第 5 步後頁面的屏幕快照

Authors DataGrid 來自:

Step5.aspx:

<asp:DataGrid id="authorsGrid" runat="server"
...
AllowPaging="true" PageSize="5"
OnPageIndexChanged="OnPageIndexChangedAuthorsGrid">
...

<property name="PagerStyle">
<asp:DataGridPagerStyle BackColor="Tan" HorizontalAlign="Right"
PageButtonCount="3" Mode="NumericPages"/>
</property>
</asp:DataGrid>

與排序類似,您必須設定幾個屬性並實施一個事件處理器,從而啟用分頁功能。啟用分頁功能的具體步驟是,將 AllowPaging 屬性設定為 true,並將 PageSize 屬性設定為一個正整數。 PageSize 屬性確定了要在單頁面中表現的數據源的值。

該樣例還展示設定 PagerStyle 屬性,從而使您可以對分頁 UI 的視覺外觀和佈局進行定制。樣例將分頁器一次展示三個頁碼按鈕,方法是將 Mode 設定為 NumericButtons,而將 PageButtonCount 屬性設定為 "3",並使其向右對其。除了這些設置,您還可以選擇「下一步」/「上一步」樣式按鈕,分頁 UI 的位置,其顏色方案,等等。

要支持分頁,就必須對 DataGrid 的 PageIndexChanged 事件進行處理,具體討論見 Step5Page.cs。

Step5Page.cs:

namespace Samples {
...

public class Step5Page : Page {

// 處理作者網格中的 PageIndexChanged 事件,以
// 更新數據
protected void OnPageIndexChangedAuthorsGrid(object sender,
DataGridPageChangedEventArgs e) {
LoadAuthorsGrid();
}
}
}

PageIndexChangedEvent 的事件處理程序只是重新加載 DataGrid,從而自動呈現數據源中所有項目的分頁視圖。事件處理器是在 DataGridPageChangedEventArgs 的一個實例中傳遞的,該實例包含關於舊的頁面索引和新的頁面索引的信息。如果根據應用程序的狀態,您確定不應更改頁面索引,則可以僅將 DataGrid 的 CurrentPageIndex 屬性設定回舊的頁面索引,跳過重新加載數據。顯式數據綁定模型使這成為可能。這裡,直到對 DataBind 進行調用時 DataGrid 的內容才得到刷新。

DataGrid 支持一種備選的分頁模式,您可以通過將 AllowCustomPaging 屬性設定為 true 而啟用該模式。在該模式中,您負責向 DataGrid 告知您的數據源中的值的總數,具體方法是設定 VirtualItemCount 屬性。一旦處於該模式,您的數據源就想必只包含當前頁面的值。在該模式中,僅需從查詢檢索最少數目的值,從而進一步優化您的數據訪問。


--------------------------------------------------------------------------------


第 6 步: 原地編輯

DataGrid 支持對其行的原地編輯。這一步使用該功能,從而允許在 Titles DataGrid 內部進行編輯。



圖 7. 完成第 6 步後的頁面

Titles DataGrid 來自:

Step6.aspx:

<asp:DataGrid id="titlesGrid" runat="server"
...
OnEditCommand="OnEditCommandTitlesGrid"
OnUpdateCommand="OnUpdateCommandTitlesGrid"
OnCancelCommand="OnCancelCommandTitlesGrid">

<property name="Columns">
<asp:BoundColumn HeaderText="ID" DataField="title_id" ReadOnly="true">
<property name="HeaderStyle">
<asp:TableItemStyle Width="100px"/>
</property>
</asp:BoundColumn>
<asp:BoundColumn HeaderText="Title" DataField="title" ReadOnly="true">
<property name="HeaderStyle">
<asp:TableItemStyle Width="250px"/>
</property>
</asp:BoundColumn>
<asp:BoundColumn HeaderText="Published" DataField="pubdate"
DataFormatString="{0:MMM yyyy}" ReadOnly="true">
<property name="HeaderStyle">
<asp:TableItemStyle Width="100px"/>
</property>
</asp:BoundColumn>
<asp:BoundColumn HeaderText="Price" DataField="price"
DataFormatString="{0:c}">
<property name="HeaderStyle">
<asp:TableItemStyle Width="50px"/>
</property>
<property name="ItemStyle">
<asp:TableItemStyle HorizontalAlign="Right"/>
</property>
</asp:BoundColumn>
<asp:EditCommandColumn EditText="Edit" CancelText="Cancel"
UpdateText="OK"/>
</property>

...
</asp:DataGrid>

通過處理控件的 EditCommand、 UpdateCommand 和 CancelCommand 事件來達到在 DataGrid 內進行編輯的目的。

Columns 集合包含一個名為 EditCommandColumn 的新的列。該列自動創建每行右側的按鈕集。為只讀模式中的各行創建 Edit 按鈕,並為編輯模式中的各行創建 Update 和 Cancel 按鈕。列的 EditText、 CancelText 和 UpdateText 屬性用來指定按鈕的文本。注意,也可以將文本設定為 HTML 標記,從而為這些按鈕使用圖像。

最後,各種列的 ReadOnly<./font> 屬性被設定為 true。這就防止對這些列中的數據進行編輯,即使列處於編輯模式。對於本樣例,只有價格字段是可編輯的,因而所有其它 BoundColumns 均被標注為只讀。

上面聲明的事件處理器在下面展示的有代碼支持的類中得到實施。

Step6Page.cs:

namespace Samples {
...

public class Step6Page : Page {

// 更新當前選定的作者並重新加載與選定內容對應的書名
// 網格
protected void LoadTitlesGrid() {
UpdateSelection();
titlesGrid.DataBind();
}

// 處理書名網格中的 CancelCommand 事件,以
// 不施用更改就結束編輯
protected void OnCancelCommandTitlesGrid(object sender,
DataGridCommandEv

相關文章: