自訂 DataList 的編輯介面 (C#)
在本教學課程中,我們將為 DataList 建立更豐富的編輯介面,其中包含 DropDownList 和 CheckBox。
簡介
DataList 中的 EditItemTemplate
標記和 Web 控制項會定義其可編輯的介面。 到目前為止,我們在所有可編輯的 DataList 範例中,可編輯的介面是由 TextBox Web 控制項所組成。 在 上述教學課程 中,我們會藉由新增驗證控件來改善編輯時間用戶體驗。
EditItemTemplate
可以進一步擴充以包含 TextBox 以外的 Web 控件,例如 DropDownLists、RadioButtonLists、Calendars 等等。 如同 TextBox,自訂編輯介面以包含其他 Web 控件時,請採用下列步驟:
- 將 Web 控制項新增至
EditItemTemplate
。 - 使用數據系結語法,將對應的數據域值指派給適當的屬性。
- 在事件處理程式中
UpdateCommand
,以程式設計方式存取 Web 控件值,並將其傳遞至適當的 BLL 方法。
在本教學課程中,我們將為 DataList 建立更豐富的編輯介面,其中包含 DropDownList 和 CheckBox。 特別是,我們將建立一個 DataList 來列出產品資訊,並允許產品名稱、供應商、類別和已停止的狀態更新 (請參閱圖 1) 。
圖 1:編輯介面包含 TextBox、兩個 DropDownList 和 CheckBox (按兩下即可檢視大小完整的影像)
步驟 1:顯示產品資訊
我們必須先建置只讀介面,才能建立DataList可編輯的介面。 從開啟CustomizedUI.aspx
資料夾的頁面EditDeleteDataList
開始,然後從 Designer,將 DataList 新增至頁面,並將其ID
屬性設定為 Products
。 從 DataList 的智慧標記中,建立新的 ObjectDataSource。 將這個新的 ObjectDataSource ProductsDataSource
命名為 ,並將其設定為從 ProductsBLL
類別 s GetProducts
方法擷取數據。 如同先前可編輯的 DataList 教學課程,我們將直接前往商業規則層來更新已編輯的產品資訊。 因此,將 UPDATE、INSERT 和 DELETE 索引標籤中的下拉式清單設定為 ([無]) 。
圖 2:將 UPDATE、INSERT 和 DELETE 索引標籤 Drop-Down 清單 設定為 ([無]) (按兩下即可檢視大小完整的映像)
設定 ObjectDataSource 之後,Visual Studio 會為 DataList 建立預設值 ItemTemplate
,其中列出每個傳回之數據欄位的名稱和值。 ItemTemplate
修改 ,讓範本列出元素中的<h4>
產品名稱,以及類別名稱、供應商名稱、價格和已停止的狀態。 此外,新增 [編輯] 按鈕,確定其 CommandName
屬性已設定為 [編輯]。 我的 ItemTemplate
宣告式標記如下:
<ItemTemplate>
<h4>
<asp:Label ID="ProductNameLabel" runat="server"
Text='<%# Eval("ProductName") %>' />
</h4>
<table border="0">
<tr>
<td class="ProductPropertyLabel">Category:</td>
<td class="ProductPropertyValue">
<asp:Label ID="CategoryNameLabel" runat="server"
Text='<%# Eval("CategoryName") %>' />
</td>
<td class="ProductPropertyLabel">Supplier:</td>
<td class="ProductPropertyValue">
<asp:Label ID="SupplierNameLabel" runat="server"
Text='<%# Eval("SupplierName") %>' />
</td>
</tr>
<tr>
<td class="ProductPropertyLabel">Discontinued:</td>
<td class="ProductPropertyValue">
<asp:Label ID="DiscontinuedLabel" runat="server"
Text='<%# Eval("Discontinued") %>' />
</td>
<td class="ProductPropertyLabel">Price:</td>
<td class="ProductPropertyValue">
<asp:Label ID="UnitPriceLabel" runat="server"
Text='<%# Eval("UnitPrice", "{0:C}") %>' />
</td>
</tr>
<tr>
<td colspan="4">
<asp:Button runat="Server" ID="EditButton"
Text="Edit" CommandName="Edit" />
</td>
</tr>
</table>
<br />
</ItemTemplate>
上述標記會使用 <產品名稱的 h4> 標題和其餘欄位的四欄 <table>
來配置產品資訊。 ProductPropertyLabel
在中Styles.css
定義的和 ProductPropertyValue
CSS 類別已在先前的教學課程中討論過。 圖 3 顯示透過瀏覽器檢視時的進度。
圖 3:[每個產品的名稱]、[供貨商]、[類別]、[已停止狀態] 和 [價格] 會顯示 (按兩下即可檢視大小完整的影像)
步驟 2:將 Web 控制項新增至編輯介面
建置自訂 DataList 編輯介面的第一個步驟是將所需的 Web 控制項新增至 EditItemTemplate
。 特別是,我們需要DropDownList作為類別、另一個用於供應商,以及已停止狀態的 CheckBox。 由於產品價格在此範例中無法編輯,因此我們可以使用標籤 Web 控件繼續顯示它。
若要自定義編輯介面,請按兩下 DataList 智慧標記中的 [編輯範本] 連結,然後從下拉式清單中選擇 EditItemTemplate
選項。 將 DropDownList 新增至 , EditItemTemplate
並將其設定 ID
為 Categories
。
圖 4:針對 [類別] 新增 DropDownList (按兩下以檢視大小完整的影像)
接下來,從DropDownList的智慧標記中,選取 [選擇數據源] 選項,然後建立名為 CategoriesDataSource
的新 ObjectDataSource。 將此 ObjectDataSource 設定為使用 CategoriesBLL
類別 s GetCategories()
方法, (請參閱圖 5) 。 接下來,DropDownList s 數據源組態精靈會提示數據欄位用於每個 ListItem
Text
和 Value
屬性。 讓DropDownList顯示 CategoryName
數據欄位,並使用 CategoryID
做為值,如圖 6 所示。
圖 5:建立名為 CategoriesDataSource
的新 ObjectDataSource (按兩下即可檢視大小完整的映像)
圖 6:設定 DropDownList 的 [顯示] 和 [值字段] (按兩下以檢視大小完整的影像)
重複這一系列的步驟,為供應商建立DropDownList。 ID
將此 DropDownList 的 設定為 Suppliers
,並將其 ObjectDataSource SuppliersDataSource
命名為 。
新增兩個DropDownLists之後,請新增已停止狀態的 CheckBox 和產品名稱的 TextBox。 分別將 ID
CheckBox 和 TextBox 的 s 設定為 Discontinued
和 ProductName
。 新增 RequiredFieldValidator,以確保使用者提供產品名稱的值。
最後,新增 [更新] 和 [取消] 按鈕。 請記住,對於這兩個按鈕,其 CommandName
屬性會分別設定為 [更新] 和 [取消]。
您可以隨意配置編輯介面。 我已選擇從只讀介面使用相同的四欄 <table>
配置,如下列宣告式語法和螢幕快照所示:
<EditItemTemplate>
<h4>
<asp:Label ID="ProductNameLabel" runat="server"
Text='<%# Eval("ProductName") %>' />
</h4>
<table border="0">
<tr>
<td class="ProductPropertyLabel">Name:</td>
<td colspan="3" class="ProductPropertyValue">
<asp:TextBox runat="server" ID="ProductName" Width="90%" />
<asp:RequiredFieldValidator ID="RequiredFieldValidator1"
ControlToValidate="ProductName"
ErrorMessage="You must enter a name for the product."
runat="server">*</asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td class="ProductPropertyLabel">Category:</td>
<td class="ProductPropertyValue">
<asp:DropDownList ID="Categories" runat="server"
DataSourceID="CategoriesDataSource"
DataTextField="CategoryName" DataValueField="CategoryID" />
</td>
<td class="ProductPropertyLabel">Supplier:</td>
<td class="ProductPropertyValue">
<asp:DropDownList ID="Suppliers" DataTextField="CompanyName"
DataSourceID="SuppliersDataSource"
DataValueField="SupplierID" runat="server" />
</td>
</tr>
<tr>
<td class="ProductPropertyLabel">Discontinued:</td>
<td class="ProductPropertyValue">
<asp:CheckBox runat="server" id="Discontinued" />
</td>
<td class="ProductPropertyLabel">Price:</td>
<td class="ProductPropertyValue">
<asp:Label ID="UnitPriceLabel" runat="server"
Text='<%# Eval("UnitPrice", "{0:C}") %>' />
</td>
</tr>
<tr>
<td colspan="4">
<asp:Button runat="Server" ID="UpdateButton" CommandName="Update"
Text="Update" />
<asp:Button runat="Server" ID="CancelButton" CommandName="Cancel"
Text="Cancel" CausesValidation="False" />
</td>
</tr>
</table>
<br />
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetCategories"
TypeName="CategoriesBLL">
</asp:ObjectDataSource>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetSuppliers"
TypeName="SuppliersBLL">
</asp:ObjectDataSource>
</EditItemTemplate>
圖 7:編輯介面的配置方式就像 Read-Only 介面 (按兩下即可檢視完整大小的影像)
步驟 3:建立 EditCommand 和 CancelCommand 事件處理程式
目前, (中沒有數據系結語法 EditItemTemplate
,但 UnitPriceLabel
從) 逐字複製的 ItemTemplate
除外。 我們會立即新增數據系結語法,但首先讓我們建立 DataList EditCommand
和 CancelCommand
事件的事件處理程式。 回想一下,事件處理程式的責任 EditCommand
是轉譯已按下 [編輯] 按鈕之 DataList 專案的編輯介面,而 CancelCommand
s 作業則是將 DataList 傳回其預先編輯狀態。
建立這兩個事件處理程式,並讓它們使用下列程式代碼:
protected void Products_EditCommand(object source, DataListCommandEventArgs e)
{
// Set the DataList's EditItemIndex property and rebind the data
Products.EditItemIndex = e.Item.ItemIndex;
Products.DataBind();
}
protected void Products_CancelCommand(object source, DataListCommandEventArgs e)
{
// Return to DataList to its pre-editing state
Products.EditItemIndex = -1;
Products.DataBind();
}
有了這兩個事件處理程式,按兩下 [編輯] 按鈕會顯示編輯介面,然後按兩下 [取消] 按鈕會將編輯的項目傳回其只讀模式。 圖 8 顯示 DataList,在 [編輯] 按鈕已針對 Chef Anton s一個[單選混合] 按兩下之後。 因為我們尚未將任何數據系結語法新增至編輯介面,所以 TextBox 是空白的、ProductName
Discontinued
未核取的 CheckBox,以及從 Categories
和 Suppliers
DropDownLists 選取的第一個專案。
圖 8:按兩下 [編輯] 按鈕會顯示編輯介面 (按鍵即可檢視大小完整的影像)
步驟 4:將 DataBinding 語法新增至編輯介面
若要讓編輯介面顯示目前的產品值,我們需要使用數據系結語法,將數據域值指派給適當的 Web 控制項值。 您可以移至 [編輯範本] 畫面,然後從 Web 控件智慧標記選取 [編輯 DataBindings] 連結,透過 Designer 套用數據系結語法。 或者,數據系結語法可以直接新增至宣告式標記。
將 ProductName
數據域值指派給 ProductName
TextBox 的 Text
屬性、 CategoryID
和 SupplierID
數據域值給 Categories
和 Suppliers
DropDownLists SelectedValue
屬性,並將 Discontinued
數據域值指派給 Discontinued
CheckBox s Checked
屬性。 進行這些變更之後,請透過 Designer 或直接透過宣告式標記,透過瀏覽器重新瀏覽頁面,然後按兩下 Chef Anton sAtivebo Mix 的 [編輯] 按鈕。 如圖 9 所示,數據系結語法已將目前的值新增至 TextBox、DropDownLists 和 CheckBox。
圖 9:按兩下 [編輯] 按鈕會顯示編輯介面 (按兩下以檢視大小完整的影像)
步驟 5:儲存 UpdateCommand 事件處理程式中的用戶變更
當使用者編輯產品並按兩下 [更新] 按鈕時,就會發生回傳,並引發DataList事件 UpdateCommand
。 在事件處理程式中,我們需要從 中的 EditItemTemplate
Web 控件讀取 值,並使用 BLL 介面來更新資料庫中的產品。 如先前教學課程中所見, ProductID
更新產品的 可透過 DataKeys
集合存取。 使用者輸入的欄位是透過 FindControl("controlID")
以程式設計方式參考 Web 控件來存取,如下列程式代碼所示:
protected void Products_UpdateCommand(object source, DataListCommandEventArgs e)
{
// Make sure the page is valid...
if (!Page.IsValid)
return;
// Read in the ProductID from the DataKeys collection
int productID = Convert.ToInt32(Products.DataKeys[e.Item.ItemIndex]);
// Read in the product name and price values
TextBox productName = (TextBox)e.Item.FindControl("ProductName");
DropDownList categories = (DropDownList)e.Item.FindControl("Categories");
DropDownList suppliers = (DropDownList)e.Item.FindControl("Suppliers");
CheckBox discontinued = (CheckBox)e.Item.FindControl("Discontinued");
string productNameValue = null;
if (productName.Text.Trim().Length > 0)
productNameValue = productName.Text.Trim();
int categoryIDValue = Convert.ToInt32(categories.SelectedValue);
int supplierIDValue = Convert.ToInt32(suppliers.SelectedValue);
bool discontinuedValue = discontinued.Checked;
// Call the ProductsBLL's UpdateProduct method...
ProductsBLL productsAPI = new ProductsBLL();
productsAPI.UpdateProduct(productNameValue, categoryIDValue, supplierIDValue,
discontinuedValue, productID);
// Revert the DataList back to its pre-editing state
Products.EditItemIndex = -1;
Products.DataBind();
}
程式代碼一開始會諮詢 Page.IsValid
屬性,以確保頁面上的所有驗證控件都有效。 如果 Page.IsValid
為True
,則會從DataKeys
集合讀取編輯的產品ProductID
值,並以程式設計方式參考 中的EditItemTemplate
數據輸入 Web 控制件。 接下來,這些 Web 控制件的值會讀入變數,然後傳遞至適當的 UpdateProduct
多載。 更新數據之後,DataList 會傳回其預先編輯狀態。
注意
我省略 了處理 BLL 和 DAL-Level 例外 狀況教學課程中新增的例外狀況處理邏輯,以便讓程式代碼保持焦點,並將這個範例設為焦點。 練習中,完成本教學課程之後,新增這項功能。
步驟 6:處理 NULL CategoryID 和 SupplierID 值
Northwind 資料庫允許NULL
數據表CategoryID
和數據SupplierID
行的值Products
。 不過,我們的編輯介面目前無法容納 NULL
值。 如果我們嘗試編輯具有其 或 資料行值的產品NULL
,我們會收到 ArgumentOutOfRangeException
類似錯誤訊息的 ,其錯誤訊息類似於:『Categories』 有 SelectedValue,因為它不存在於專案清單中。SupplierID
CategoryID
此外,目前無法將產品類別或供應商值從非NULL
值變更為NULL
一個類別。
若要支援 NULL
類別和供應商 DropDownLists 的值,我們需要新增額外的 ListItem
。 我選擇使用 (None) 做為此 的值ListItem
,但您可以視需要將它變更為Text
其他 (,例如空字串) 。 最後,請記得將DropDownLists AppendDataBoundItems
設定為 True
;如果您忘記這麼做,系結至DropDownList 的類別和供貨商將會覆寫以靜態方式新增 ListItem
的 。
進行這些變更之後,DataList s EditItemTemplate
中的DropDownLists標記看起來應該如下所示:
<asp:DropDownList ID="Categories" DataSourceID="CategoriesDataSource"
DataTextField="CategoryName" DataValueField="CategoryID" runat="server"
SelectedValue='<%# Eval("CategoryID") %>' AppendDataBoundItems="True">
<asp:ListItem Value=" Selected="True">(None)</asp:ListItem>
</asp:DropDownList>
...
<asp:DropDownList ID="Suppliers" DataSourceID="SuppliersDataSource"
DataTextField="CompanyName" DataValueField="SupplierID" runat="server"
SelectedValue='<%# Eval("SupplierID") %>' AppendDataBoundItems="True">
<asp:ListItem Value=" Selected="True">(None)</asp:ListItem>
</asp:DropDownList>
注意
靜態 ListItem
可以透過 Designer 或直接透過宣告式語法新增至DropDownList。 新增DropDownList專案來代表資料庫 NULL
值時,請務必透過宣告式語法來新增 ListItem
。 如果您在 Designer 中使用 ListItem
Collection 編輯器,產生的宣告式語法會在指派空白字串時完全省略Value
設定,建立宣告式標記,例如: <asp:ListItem>(None)</asp:ListItem>
。 雖然這看起來可能無害,但遺失 Value
會導致DropDownList在其位置使用 Text
屬性值。 這表示如果選取此選項 NULL
ListItem
, (None) 的值將會嘗試指派給產品數據欄位 (CategoryID
或 SupplierID
,在本教學課程中) ,這會導致例外狀況。 藉由明確設定 Value=""
, NULL
當選取 時 NULL
ListItem
,會將值指派給產品數據欄位。
請花點時間透過瀏覽器檢視我們的進度。 編輯產品時, Categories
請注意 和 Suppliers
DropDownLists在DropDownList開頭都有 (None) 選項。
圖 10: Categories
和 Suppliers
DropDownList 包含 [無 (]) 選項 (按兩下即可檢視完整大小的影像)
若要將 (None) 選項儲存為資料庫 NULL
值,我們必須返回 UpdateCommand
事件處理程式。 將 categoryIDValue
和 supplierIDValue
變數變更為可為 Null 的整數,並只指派 DropDownList Nothing
s SelectedValue
不是空字串時以外的值:
int? categoryIDValue = null;
if (!string.IsNullOrEmpty(categories.SelectedValue))
categoryIDValue = Convert.ToInt32(categories.SelectedValue);
int? supplierIDValue = null;
if (!string.IsNullOrEmpty(suppliers.SelectedValue))
supplierIDValue = Convert.ToInt32(suppliers.SelectedValue);
使用此變更時,如果使用者從任一下拉式清單中 (選取了 [無) ] 選項,則會將 的值 Nothing
傳入 UpdateProduct
BLL 方法中,這兩個 NULL
清單對應至資料庫值。
摘要
在本教學課程中,我們已瞭解如何建立更複雜的 DataList 編輯介面,其中包含三個不同的輸入 Web 控件 TextBox、兩個 DropDownList 和 CheckBox 以及驗證控件。 建置編輯介面時,不論使用的 Web 控件為何,步驟都相同:一開始,請先將 Web 控件新增至 DataList s EditItemTemplate
;使用數據系結語法來指派具有適當 Web 控件屬性的對應數據域值;在事件處理程式中 UpdateCommand
,以程式設計方式存取 Web 控件及其適當屬性, 將其值傳遞至 BLL。
建立編輯介面時,不論它是由 TextBox 或不同 Web 控件的集合所組成,請務必正確地處理資料庫 NULL
值。 考慮 NULL
s 時,您不僅必須在編輯介面中正確顯示現有的 NULL
值,也提供將值標示為 NULL
的方法。 對於 DataLists 中的 DropDownList,這通常表示將 屬性明確設定為空字串的靜態ListItem
Value
, () Value=""
,並將一些程式代碼新增至UpdateCommand
事件處理程式,以判斷是否已NULL``ListItem
選取 。
快樂的程序設計!
關於作者
Scott Mitchell 是 1998 年以來,1998 年與 Microsoft Web 技術合作的 七篇 ASP/ASP.NET 書籍和 4GuysFromRolla.com 作者。 Scott 是獨立的顧問、訓練者和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以透過mitchell@4GuysFromRolla.com部落格連到,也可以透過其部落格來存取,網址為 http://ScottOnWriting.NET。
特別感謝
本教學課程系列是由許多實用的檢閱者所檢閱。 本教學課程的首席檢閱者是 Dennis Patterson、David Suru 和 Randy Schmidt。 想要檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com。
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應