使用 ASP+ DataGrid 控件來創建主視圖/詳細資料視圖 (2) - 中國WEB開發者網絡 (http://www.webasp.net) -- 技術教程 (http://www.webasp.net/article/) --- 使用 ASP+ DataGrid 控件來創建主視圖/詳細資料視圖 (2) (http://www.webasp.net/article/18/17250.htm) |
| -- 作者:未知 -- 發佈日期: 2005-03-30 |
| Step6Page.cs:
namespace Samples { ... public class Step6Page : Page { // 更新當前選定的作者並重新加載與選定內容對應的書名 // 網格 protected void LoadTitlesGrid() { UpdateSelection(); titlesGrid.DataBind(); } // 處理書名網格中的 CancelCommand 事件,以 // 不施用更改就結束編輯 protected void OnCancelCommandTitlesGrid(object sender, DataGridCommandEventArgs e) { titlesGrid.EditItemIndex = -1; LoadTitlesGrid(); } // 處理書名網格中的 EditCommand 事件,以 // 開始編輯某一行 protected void OnEditCommandTitlesGrid(object sender, DataGridCommandEventArgs e) { titlesGrid.EditItemIndex = e.Item.ItemIndex; LoadTitlesGrid(); } // 處理書名網格中的 UpdateCommand 事件,以施用 // 所作的更改並結束編輯 protected void OnUpdateCommandTitlesGrid(object sender, DataGridCommandEventArgs e) { TextBox priceText = (TextBox)e.Item.FindControl("Column3Control"); string newPrice = priceText.Text.Substring(1); DataSet ds = GetSessionData(); DataTable titlesTable = ds.Tables["Title"]; string titleID = (string)titlesGrid.DataKeys[e.Item.ItemIndex]; DataRow[] rows = titlesTable.Select("title_id = '" + titleID + "'"); DataRow editRow = rows[0]; editRow.BeginEdit(); editRow["price"] = newPrice; editRow.EndEdit(); editRow.AcceptChanges(); titlesGrid.EditItemIndex = -1; LoadTitlesGrid(); } } } EditCommand 事件是在單擊 Edit 按鈕時引發的。只需將 DataGrid 的 EditItemIndex 屬性設定為包含被單擊按鈕的項目的索引的屬性。要防止編輯某一個別行,不採取任何動作就返回。另外,要繼續進行編輯,就必須重新加載數據源並調用 DataBind。這通過調用 LoadTitlesGrid 方法來完成。 您必須處理的第二個事件就是 CancelCommand 事件。這是單擊 Cancel 按鈕時引發的。實施十分類似於前一處理器。如想結束編輯,則只需將 EditItemIndex 屬性重置為 ?,並重新加載數據源。如果需要維持行的編輯模式,則僅需不採取任何動作就從函數返回即可。 要處理的最後一個事件就是 UpdateCommand 事件,這是單擊 Update 按鈕時引發的。這裡是實際工作發生的地方。從存在於項目中的控件抽取新的值,然後更新數據源。一旦將新的值使用完畢,就將 EditItemIndex 重置為 ?,以返回到只讀模式,並連同其數據源一起重新加載控件。對於前兩個事件,您可以不採取任何動作就從該函數返回,以保持該行的編輯模式狀態。 這一步又再次舉例說明控件中實施的顯式數據綁定模型。在這一實施情形中,只在某行的狀態從只讀模式更改為編輯模式或相反時才需要數據源。注意, DataGrid 自身並不更新其數據源。實質上,數據綁定是單向的。採用本模型的目的在於讓您擁有對數據源更新的控制。在大多數典型的應用程序中,更新需要預處理,並且是由業務對像或已存儲的過程來調用的。另外,單向數據綁定並不要求每個時間都有實時的數據源。 -------------------------------------------------------------------------------- 第 7 步: 使用模板 DataGrid 控件通過使用 TemplateColumns,支持列內模板。可以完全自由地決定與這些列相關聯的單元格的內容。這一步使用 TemplateColumn 來增強首先在前一步中實施的編輯支持。 圖 8. 完成第 7 步後的頁面 Titles DataGrid 來自: Step7.aspx: <asp:DataGrid id="titlesGrid" runat="server" ...> <property name="Columns"> ... <asp:TemplateColumn HeaderText="Price"> <template name="ItemTemplate"> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "price", "{0:c}") %>'/> </template> <template name="EditItemTemplate"> <asp:RequiredFieldValidator runat="server" ControlToValidate="priceText" Display="Dynamic"> <img src="Error.gif" height="16" width="16" title="Required" align="absmiddle"> </asp:RequiredFieldValidator> <asp:RegularExpressionValidator runat="server" ControlToValidate="priceText" Display="Dynamic" ValidationExpression="\$[0-9]+(\.[0-9][0-9]?)?"> <img src="Error.gif" height="16" width="16" title="Invalid currency value" align="absmiddle"> </asp:RegularExpressionValidator> <asp:TextBox id="priceText" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "price", "{0:c}") %>' Width="45px" BorderStyle="Solid" BorderWidth="1px" BorderColor="Black"> </asp:TextBox> </template> <property name="HeaderStyle"> <asp:TableItemStyle Width="50px"/> </property> <property name="ItemStyle"> <asp:TableItemStyle HorizontalAlign="Right"/> </property> </asp:TemplateColumn> </property> ... </asp:DataGrid> 控件的聲明展示將 TemplateColumn 添加到 Columns 集合,以替代價格字段的 BoundColumn。 TemplateColumns 是 DataGrid 的另一擴展機制。可以將其用於對 DataGrid 所創建的表格式佈局內所表現的 UI 進行完全定制。 TemplateColumn 還提供模板屬性,比如 ItemTemplate 和 EditItemTemplate,從而您可以指定應當用於與列相關聯的單元格內的控件。 在本例中, ItemTemplate 包含一個 Label 控件,其 Text 屬性綁定到價格字段。這實質上在模仿 BoundColumn 的功能。 有意思的是, EditItemTemplate 模板用於處於編輯模式中的單元格。樣例將一個 TextBox 放入已綁定到價格字段的模板中。這樣就提供了與 BoundColumn 相同的功能。 模板包含各種各樣的增強性能。首先,該模板允許對 TextBox 進行更大的控制,從而您可以創建在視覺上更有魅力的編輯 UI。其次,允許您放置驗證控件,從而可以進行原地驗證。在本樣例中, RequiredFieldValidator 確保 TextBox 總是包含一個值,而 RegularExpressionValidator 確保文本包含一個有效的貨幣值。該功能的最令人興奮的一個方面就是自動進行客戶機端驗證。 ASP+ 驗證控件自動進行客戶機端驗證,並開啟功能豐富的瀏覽器客戶機上的錯誤指示器,從而無須往返過程和回落到為下級客戶機進行服務器端驗證。 Step7Page.cs: namespace Samples { ... public class Step7Page : Page { // 處理書名網格中的 UpdateCommand 事件,以施用 // 所作的更改並結束編輯 (當頁面處於有效狀態時) protected void OnUpdateCommandTitlesGrid(object sender, DataGridCommandEventArgs e) { if (IsValid) { TextBox priceText = (TextBox)e.Item.FindControl("priceText"); string newPrice = priceText.Text.Substring(1); DataSet ds = GetSessionData(); DataTable titlesTable = ds.Tables["Title"]; string titleID = (string)titlesGrid.DataKeys[e.Item.ItemIndex]; DataRow[] rows = titlesTable.Select("title_id = '" + titleID + "'"); DataRow editRow = rows[0]; editRow.BeginEdit(); editRow["price"] = newPrice; editRow.EndEdit(); editRow.AcceptChanges(); titlesGrid.EditItemIndex = -1; LoadTitlesGrid(); } } } } 對支持代碼的唯一變更與繼續對數據源進行更新之前檢查頁面的有效性有關。驗證控件會自動更新頁面的 IsValid 屬性。 檢查有效性是在 UpdateCommand 事件處理器中完成的。如第 6 步中所述,不採取任何動作就從事件處理器返回,會保持行的編輯模式。因此,當,且僅當頁面處於有效狀態時,才會執行所有的更新邏輯。 證實控件還會在無效時自動顯示其錯誤消息,且無需編寫任何補充代碼。 -------------------------------------------------------------------------------- 第 8 步: 定制列 正如到目前您所看到的, DataGrid 控件支持標準的列集,諸如 BoundColumn、 ButtonColumn 和 TemplateColumn。該控件還允許您用自己的列類型對控件進行擴展。這些新的列提供了高度的靈活性。這一步實施一個名為 ImageColumn 的定制列,該列用於在單元格中,為帶有圖像 URL 數據綁定的每行顯示一個圖像。 圖 9. 完成第 8 步後的頁面 Titles DataGrid 以及 ImageColumn 的聲明來自: Step8.aspx:Step8.aspx: <%@ Register TagPrefix="s" Namespace="Samples"%> ... <asp:DataGrid id="titlesGrid" runat="server" ...> <property name="Columns"> <s:ImageColumn ImageField="title_id" ImageFormatString="images/Title-{0}.gif"/> </property> ... </asp:DataGrid> 本頁面包含一個寄存器指令,用於映射 <s:ImageColumn> 標記,以表示 Samples.ImageColumn 類。 DataGrid 的聲明展示添加到 DataGrid 的 Columns 集合的 ImageColumn。 還展示 ImageField 和 ImageFormatString 集,因而圖像是以包含與特定行相關聯的標題 ID 的 URL 為依據的。其工作原理與第 2 步中所使用的 HyperLinkColumn 十分類似。 ImageColumn.cs: namespace Samples { ... public class ImageColumn : Column { private PropertyDescriptor imageFieldDesc; public ImageColumn() { } public string ImageField { get { object o = State["ImageField"]; return (o != null) ? (string)o : String.Empty; } set { State["ImageField"] = value; } } public string ImageFormatString { get { object o = State["ImageFormatString"]; return (o != null) ? (string)o : String.Empty; } set { State["ImageFormatString"] = value; } } // 在與該列相關聯的單元格中創建 // 控件 public override void InitializeCell(TableCell cell, int columnIndex, ListItemType itemType) { base.InitializeCell(cell, columnIndex, itemType); if ((itemType == ListItemType.Item) || (itemType == ListItemType.AlternatingItem) || (itemType == ListItemType.SelectedItem) || (itemType == ListItemType.EditItem)) { Image image = new Image(); image.ID = Column.GetColumnControlID(columnIndex, -1); cell.Controls.Add(image); if (ImageField.Length != 0) { image.AddOnDataBind(new EventHandler(this.OnDataBindColumn)); } } } // 將數據載入在 InitializeCell 中創建的控件 private void OnDataBindColumn(object sender, EventArgs e) { Image boundImage = (Image)sender; DataGridItem item = (DataGridItem)boundImage.NamingContainer; object dataItem = item.DataItem; if (IsFirstDataBind()) { string imageField = ImageField; imageFieldDesc = TypeDescriptor.GetProperties(dataItem)[imageField]; if (imageFieldDesc == null) { throw new Exception("Invalid property: '" + imageField + "'"); } OnFirstDataBindHandled(); } object data = imageFieldDesc.GetValue(dataItem); if (data != null) { string format = ImageFormatString; if (format.Length != 0) { boundImage.ImageUrl = String.Format(format, data); } else { boundImage.ImageUrl = data.ToString(); } } } } } DataGrid 控件所使用的每一列均由抽像的 Column 類派生而來。 列類型實施各種各樣的屬性 (諸如 HeaderText) 以及所有列類型所公用的樣式。 ImageColumn 類用於添加針對其具體功能的屬性,諸如 ImageField 和 ImageFormatString 屬性。實施這些屬性,是通過將各值存入列的 State 中實現的。列的狀態,在 DataGrid 控件的往返過程中自動得到保持。 每列所超控的最為重要的虛擬方法就是 InitializeCell 方法。 DataGrid 促使每列初始化與該列相關聯的單元格。實施本方法時,列創建其所需要的控件,並將它們添加為單元格的子單元格。所創建的控件可能會隨 itemType 參數的不同而不同,該參數指示包含單元格的列的 ItemType 屬性。 Column 類自身包含用於產生標頭和標尾的邏輯。 ImageColumn 在進行自我實施時,只是創建一個 Image 控件。它還向 Image 的 DataBind 屬性添加一個事件處理器。 一旦將列創建完畢, DataGrid 就對其進行數據綁定。在該進程中,允許列借助與列相關聯的數據對其在 InitializeCell 中創建的控件進行定制。 ImageColumn 檢索其所綁定的字段的值,使用用戶所指定的格式生成一個 URL,然後使用結果字符串來設定圖像的 ImageUrl 屬性。 -------------------------------------------------------------------------------- 結論 DataGrid 控件簡化了多個常見 Web 應用情形,其中包括只讀報表到交互式應用程序 UI。該控件優於傳統的 ASP 編程。它將轉換對像模型操作和數據綁定所需的邏輯封裝進與瀏覽器無關的 HTML 表現功能。還將處理回傳數據以及轉換客戶機事件的詳細資料封狀進服務器事件。 該控件設計用於無須作出太多開發努力就可以表現您的數據。隨著應用要求的改變,以及您開始使用 DataGrid 的各種功能,您可以逐步添加其它功能。 現在 Microsoft® .NET SDK 和 Framework 中就已提供該控件。 SDK 還包含補充文檔和多個樣例,可用於快速啟動;兩者均實施本文中所提供的材料。 |
| webasp.net |