自訂資料修改介面 (C#)
在本教學課程中,我們將瞭解如何使用替代輸入 Web 控件取代標準 TextBox 和 CheckBox 控制件,以自定義可編輯 GridView 的介面。
簡介
GridView 和 DetailsView 所使用的 BoundFields 和 CheckBoxFields 可簡化修改數據的程式,因為能夠轉譯只讀、可編輯和可插入的介面。 這些介面可以轉譯,而不需要新增任何其他宣告式標記或程序代碼。 不過,BoundField 和 CheckBoxField 的介面缺少在真實世界案例中通常需要的自定義性。 若要在 GridView 或 DetailsView 中自定義可編輯或可插入的介面,我們需要改用 TemplateField。
在 上述教學課程 中,我們已瞭解如何藉由新增驗證 Web 控件來自定義數據修改介面。 在本教學課程中,我們將探討如何自定義實際的數據收集 Web 控件,並以替代的輸入 Web 控件取代 BoundField 和 CheckBoxField 的標準 TextBox 和 CheckBox 控件。 特別是,我們將建置可編輯的 GridView,以允許更新產品名稱、類別、供應商和已停止的狀態。 編輯特定數據列時,類別和供應商欄位會轉譯為DropDownLists,其中包含一組可用的類別和供應商可供選擇。 此外,我們將以 RadioButtonList 控件取代 CheckBoxField 的預設 CheckBox,以提供兩個選項:“Active” 和 “Discontinued”。
圖 1:GridView 的編輯介面包含DropDownLists和 RadioButtons (按兩下即可檢視大小完整的影像)
步驟 1:建立適當的UpdateProduct
多載
在本教學課程中,我們將建置可編輯的 GridView,以允許編輯產品名稱、類別、供應商和已停止的狀態。 因此,我們需要接受五個輸入參數的多載,這四個 UpdateProduct
乘積值加上 ProductID
。 如同先前的多載,這將會:
- 從指定
ProductID
之的資料庫擷取產品資訊。 ProductName
更新、CategoryID
、SupplierID
和Discontinued
欄位和- 透過 TableAdapter
Update()
的 方法將更新要求傳送至 DAL。
為了簡潔起見,對於這個特定多載,我省略了商務規則檢查,以確保標示為已停止的產品不是其供應商提供的唯一產品。 如果您想要,或最好將邏輯重構為個別方法,請隨意將其新增至 。
下列程式代碼顯示 類別中的ProductsBLL
新UpdateProduct
多載:
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, false)]
public bool UpdateProduct(string productName, int? categoryID,
int? supplierID, bool discontinued, int productID)
{
Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
if (products.Count == 0)
// no matching record found, return false
return false;
Northwind.ProductsRow product = products[0];
product.ProductName = productName;
if (supplierID == null) product.SetSupplierIDNull();
else product.SupplierID = supplierID.Value;
if (categoryID == null) product.SetCategoryIDNull();
else product.CategoryID = categoryID.Value;
product.Discontinued = discontinued;
// Update the product record
int rowsAffected = Adapter.Update(product);
// Return true if precisely one row was updated, otherwise false
return rowsAffected == 1;
}
步驟 2:製作可編輯的 GridView
新增多載后 UpdateProduct
,即可建立可編輯的 GridView。 CustomizedUI.aspx
開啟資料夾中的頁面EditInsertDelete
,並將 GridView 控制項新增至 Designer。 接下來,從 GridView 的智慧標記建立新的 ObjectDataSource。 設定 ObjectDataSource 以透過 ProductBLL
類別 GetProducts()
的 方法擷取產品資訊,並使用我們剛才建立的多載來更新產品數據 UpdateProduct
。 從 [INSERT] 和 [刪除] 索引標籤中,從下拉式清單中選取 ([無) ]。
圖 2:將 ObjectDataSource 設定為使用 Just Created 的多 UpdateProduct
載 (按兩下即可檢視大小完整的映像)
如我們在數據修改教學課程中所見,Visual Studio 所建立 ObjectDataSource 的宣告式語法會將 屬性指派 OldValuesParameterFormatString
給 original_{0}
。 當然,這不會與商業規則層搭配使用,因為我們的方法不會預期會傳入原始 ProductID
值。 因此,如我們在先前的教學課程中所做的一樣,請花點時間從宣告式語法中移除此屬性指派,或改為將此屬性的值設定為 {0}
。
這項變更之後,ObjectDataSource 的宣告式標記看起來應該如下所示:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
SelectMethod="GetProducts" TypeName="ProductsBLL"
UpdateMethod="UpdateProduct">
<UpdateParameters>
<asp:Parameter Name="productName" Type="String" />
<asp:Parameter Name="categoryID" Type="Int32" />
<asp:Parameter Name="supplierID" Type="Int32" />
<asp:Parameter Name="discontinued" Type="Boolean" />
<asp:Parameter Name="productID" Type="Int32" />
</UpdateParameters>
</asp:ObjectDataSource>
請注意,OldValuesParameterFormatString
屬性已移除,而且我們的多載所預期的UpdateProduct
每個輸入參數集合中有 UpdateParameters
。Parameter
雖然 ObjectDataSource 設定為只更新產品值的子集,但 GridView 目前會顯示 所有 產品欄位。 請花點時間編輯 GridView,以便:
- 它只包含
ProductName
、 、SupplierName
CategoryName
BoundFields 和Discontinued
CheckBoxField CategoryName
在 CheckBoxField)Discontinued
左側 (之前顯示的 和SupplierName
字段CategoryName
和SupplierName
BoundFields 的HeaderText
屬性分別設定為 “Category” 和 “Supplier”- 啟用編輯支援 (核 GridView 智慧標記中的 [啟用編輯] 複選框)
這些變更之後,Designer 看起來會類似圖 3,且 GridView 的宣告式語法如下所示。
圖 3:從 GridView 移除不需要的欄位 (按兩下即可檢視大小完整的影像)
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
<Columns>
<asp:BoundField DataField="ProductName"
HeaderText="ProductName" SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
ReadOnly="True"
SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier"
ReadOnly="True"
SortExpression="SupplierName" />
<asp:CheckBoxField DataField="Discontinued"
HeaderText="Discontinued" SortExpression="Discontinued" />
</Columns>
</asp:GridView>
此時 GridView 的唯讀行為已完成。 檢視數據時,每個產品都會轉譯為 GridView 中的數據列,其中顯示產品的名稱、類別、供應商和已停止的狀態。
圖 4:GridView 的 Read-Only 介面已完成 (按兩下即可檢視大小完整的影像)
注意
如 插入、更新和刪除數據概觀教學課程所述,在預設行為) 啟用 GridView 檢視 (狀態非常重要。 如果您將 GridView 的 EnableViewState
屬性設定為 false
,則會執行不小心刪除或編輯記錄的並行用戶風險。
步驟 3:針對類別和供應商編輯介面使用DropDownList
回想一下,ProductsRow
物件包含CategoryID
、 SupplierID
CategoryName
和 SupplierName
屬性,可提供資料庫數據表中Products
實際的外鍵識別碼值,以及和 Suppliers
數據表中的Categories
對應Name
值。 ProductRow
的 CategoryID
和 SupplierID
可以讀取和寫入,而 CategoryName
和 SupplierName
屬性則會標示為唯讀。
由於和 屬性的CategoryName
唯讀狀態,對應的 BoundFields 已將其ReadOnly
屬性設定為 true
,以防止在編輯數據列時修改這些SupplierName
值。 雖然我們可以將 ReadOnly
屬性設定為 false
, CategoryName
但會在編輯期間將 和 SupplierName
BoundFields 轉譯為 TextBox,但當使用者嘗試更新產品時,這類方法會導致例外狀況,因為沒有 UpdateProduct
採用 CategoryName
和 SupplierName
輸入的多載。 事實上,我們不想基於兩個原因建立這類多載:
- 資料表
Products
沒有SupplierName
或CategoryName
欄位,但SupplierID
和CategoryID
。 因此,我們想要將方法傳遞這些特定的標識符值,而不是其查閱數據表的值。 - 要求使用者輸入供應商或類別的名稱小於理想,因為它需要使用者知道可用的類別和供應商及其正確的拼字。
當在只讀模式 (時,供應商和類別欄位應該會顯示類別和供應商的名稱,因為它現在) 和編輯時適用選項的下拉式清單。 使用下拉式清單,終端使用者可以快速查看有哪些類別和供應商可供選擇,並更輕鬆地選擇它們。
為了提供此行為,我們需要將 SupplierName
和 CategoryName
BoundFields 轉換成 TemplateFields,其 ItemTemplate
會發出 SupplierName
和 CategoryName
值,並使用 EditItemTemplate
DropDownList 控件來列出可用的類別和供應商。
Categories
新增和Suppliers
DropDownLists
從將 SupplierName
和 CategoryName
BoundFields 轉換成 TemplateFields 開始,方法是:按兩下 GridView 智慧標記中的 [編輯資料行] 連結;從左下方的清單選取 BoundField;然後按兩下 [將此欄位轉換成 TemplateField] 連結。 轉換程式會建立包含 和 EditItemTemplate
的 TemplateFieldItemTemplate
,如下列宣告式語法所示:
<asp:TemplateField HeaderText="Category" SortExpression="CategoryName">
<EditItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Eval("CategoryName") %>'></asp:Label>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Bind("CategoryName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
由於 BoundField 標示為唯讀,因此 和 EditItemTemplate
都包含標籤 Web 控件,ItemTemplate
其 Text
屬性系結至適用的數據欄位 (,在上述語法中 CategoryName
) 。 我們需要修改 EditItemTemplate
,以DropDownList控件取代標籤 Web 控制項。
如先前教學課程中所見,範本可以透過 Designer 或直接從宣告式語法進行編輯。 若要透過 Designer 加以編輯,請按下 GridView 智慧標記中的 [編輯範本] 連結,然後選擇使用 [類別] 字段的 EditItemTemplate
。 移除標籤 Web 控制件,並將它取代為 DropDownList 控制項,並將 DropDownList 的 ID 屬性設定為 Categories
。
圖 5:移除 TexBox 並將 DropDownList 新增至 EditItemTemplate
(按兩下即可檢視大小完整的影像)
接下來,我們需要將DropDownList填入可用的類別。 按兩下DropDownList智慧標記中的 [選擇資料源] 連結,並選擇建立名為 CategoriesDataSource
的新 ObjectDataSource。
圖 6:建立名為 CategoriesDataSource
的新 ObjectDataSource 控件 (按兩下即可檢視大小完整的映射)
若要讓這個 ObjectDataSource 傳回所有類別,請將它系結至 CategoriesBLL
類別的 GetCategories()
方法。
圖 7:將 ObjectDataSource 系結至 CategoriesBLL
的方法 GetCategories()
(按兩下以檢視大小完整的影像)
最後,設定DropDownList的設定, CategoryName
讓字段顯示在每個DropDownList ListItem
中,以及 CategoryID
做為值的欄位。
圖 8:顯示 CategoryName
欄位,並使用 CategoryID
做為 [值] (按兩下即可檢視大小完整的影像)
進行這些變更之後,TemplateField 中的 宣告CategoryName
式標記EditItemTemplate
會同時包含DropDownList和 ObjectDataSource:
<asp:TemplateField HeaderText="Category" SortExpression="CategoryName">
<EditItemTemplate>
<asp:DropDownList ID="Categories" runat="server"
DataSourceID="CategoriesDataSource"
DataTextField="CategoryName" DataValueField="CategoryID">
</asp:DropDownList>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Bind("CategoryName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
注意
中的 EditItemTemplate
DropDownList必須啟用其檢視狀態。 我們很快就會將數據系結語法新增至DropDownList的宣告式語法和數據系結命令,例如 Eval()
,而且 Bind()
只能出現在已啟用檢視狀態的控件中。
重複這些步驟,將名為 Suppliers
的 DropDownList 新增至 SupplierName
TemplateField 的 EditItemTemplate
。 這牽涉到將DropDownList新增至 EditItemTemplate
並建立另一個 ObjectDataSource。 Suppliers
不過,DropDownList 的 ObjectDataSource 應該設定為叫SuppliersBLL
用類別GetSuppliers()
的方法。 此外,設定 Suppliers
DropDownList以顯示欄位, CompanyName
並使用 SupplierID
字段作為其 ListItem
的值。
將 DropDownLists 新增至兩 EditItemTemplate
個 s 之後,請在瀏覽器中載入頁面,然後按兩下 Chef Anton 的 Cajun 季產品 [編輯] 按鈕。 如圖 9 所示,產品的類別和供應商數據行會轉譯為下拉式清單,其中包含可供選擇的可用類別和供應商。 不過請注意,根據預設,系統會選取這兩個下拉式清單中的 第一 個專案, (供應專案作為供貨商) ,即使 Chef Anton's Cajun Seasoning 是 New#Cajun Delights 提供的 Condiment。
圖 9:預設會選取 Drop-Down 清單 中的第一個專案, (按兩下即可檢視完整大小的影像)
此外,如果您按兩下 [更新],您會發現產品的 CategoryID
和 SupplierID
值設定為 NULL
。 這兩個不想要的行為都是造成,因為 中的 EditItemTemplate
DropDownLists不會系結至基礎產品數據中的任何數據欄位。
將DropDownList系結至CategoryID
和SupplierID
數據欄位
若要讓編輯的產品類別和供應商下拉式清單設定為適當的值,並在按兩下 [更新] 時將這些值傳回 BLL 的 UpdateProduct
方法,我們必須使用雙向數據系結,將 DropDownLists SelectedValue
的屬性系結至 CategoryID
和 SupplierID
數據欄位。 若要使用 Categories
DropDownList來完成這項作業,您可以直接新增 SelectedValue='<%# Bind("CategoryID") %>'
至宣告式語法。
或者,您可以透過 Designer 編輯範本,然後按兩下DropDownList智慧標記中的 [編輯 DataBindings] 連結,來設定 DropDownList 的數據系結。 接下來,指示 SelectedValue
屬性應該使用雙向數據系結來系結至 CategoryID
字段, (請參閱圖 10) 。 重複宣告式或 Designer 程式,將數據欄位系結SupplierID
至 Suppliers
DropDownList。
圖 10:使用 Two-Way Databinding 將 系結 CategoryID
至 DropDownList 的屬性 SelectedValue
(按兩下即可檢視完整大小的影像)
一旦系結套用至 SelectedValue
兩個DropDownLists的屬性,編輯過的產品類別和供應商數據行就會預設為目前產品的值。 按兩下 [更新] 時, CategoryID
所選取下拉式清單專案的 和 SupplierID
值將會傳遞至 UpdateProduct
方法。 圖 11 顯示新增數據系結語句之後的教學課程;請注意 Chef Anton 的 Cajun 季的選取下拉式清單專案如何正確串連和新的新甜果快樂。
圖 11:依預設會選取編輯產品的目前類別和供應商值, (按兩下即可檢視完整大小的影像)
處理NULL
值
數據表CategoryID
中的 Products
和 SupplierID
數據行可以是 NULL
,但 中的 EditItemTemplate
DropDownLists不包含代表值的清單專案NULL
。 這有兩個結果:
- 使用者無法使用我們的介面,將產品的類別或供應商從非
NULL
值變更為NULL
非值 - 如果產品有
NULL
CategoryID
或SupplierID
,按兩下 [編輯] 按鈕將會導致例外狀況。 這是因為NULL
語句中Bind()
(或SupplierID
) 所CategoryID
傳回的值不會對應到DropDownList中的值, (DropDownList 會在其SelectedValue
屬性設定為不在清單專案集合中的值時擲回例外狀況) 。
為了支援 NULL
CategoryID
和 SupplierID
值,我們需要將另一個 ListItem
新增至每個DropDownList來代表 NULL
值。 在 [使用DropDownList 篩選主要/詳細數據篩選 ] 教學課程中,我們已瞭解如何將其他 ListItem
專案新增至數據系結 DropDownList,其中包含將DropDownList 的 AppendDataBoundItems
屬性設定為 true
,並手動新增其他 ListItem
。 不過,在上一ListItem
Value
個教學課程中,我們已使用 的 -1
新增 。 不過,ASP.NET 中的數據系結邏輯會自動將空白字串 NULL
轉換成值,反之亦然。 因此,在本教學課程中,我們希望 ListItem
的 Value
是空字串。
首先,將 DropDownLists 的 AppendDataBoundItems
屬性設定為 true
。 接下來,將 NULL
ListItem
下列 <asp:ListItem>
專案新增至每個DropDownList,讓宣告式標記看起來像這樣:
<asp:DropDownList ID="Categories" runat="server"
DataSourceID="CategoriesDataSource" DataTextField="CategoryName"
DataValueField="CategoryID" SelectedValue='<%# Bind("CategoryID") %>'
AppendDataBoundItems="True">
<asp:ListItem Value="">(None)</asp:ListItem>
</asp:DropDownList>
我選擇使用 「 (None) 」 做為此 的 ListItem
Text 值,但如果您想要的話,也可以將其變更為空白字串。
注意
如我們在 [使用DropDownList篩選的主要/詳細資料篩選] 教學課程中所見,ListItem
可以透過 Designer 將 新增至DropDownList,方法是單擊 屬性視窗 (中的DropDownList Items
屬性,以顯示ListItem
集合 編輯器) 。 不過,請務必透過宣告式語法新增 NULL
ListItem
本教學課程的 。 如果您使用 ListItem
Collection 編輯器,產生的宣告式語法會在指派空白字串時完全省略Value
設定,建立宣告式標記,例如: <asp:ListItem>(None)</asp:ListItem>
。 雖然這看起來可能無害,但遺漏的 Value 會導致DropDownList在其位置使用 Text
屬性值。 這表示如果選取此選項 NULL
ListItem
,則會嘗試將 「 (None) 」 值指派給 CategoryID
,這會導致例外狀況。 藉由明確設定 Value=""
,就會在選取 時NULL
ListItem
將值指派給 CategoryID
。NULL
針對供應商 DropDownList 重複這些步驟。
有了這個額外的 ListItem
,編輯介面現在可以將值指派 NULL
給 Product 的 CategoryID
和 SupplierID
欄位,如圖 12 所示。
圖 12:選擇 ([無) ] 以指派 NULL
產品類別或供貨商的值 (按兩下即可檢視全大小的影像)
步驟 4:針對已停止狀態使用 RadioButtons
目前產品 Discontinued
的數據欄位會使用 CheckBoxField 來表示,這會呈現唯讀數據列的停用複選框,以及正在編輯之數據列的已啟用複選框。 雖然此使用者介面通常適合,但我們可以視需要使用TemplateField加以自定義。 在本教學課程中,讓我們將 CheckBoxField 變更為使用 RadioButtonList 控件的 TemplateField,其中包含兩個選項 “Active” 和 “Discontinued”,讓使用者可以從中指定產品 Discontinued
的值。
首先,將 Discontinued
CheckBoxField 轉換成 TemplateField,這會使用 ItemTemplate
和 EditItemTemplate
建立 TemplateField。 這兩個範本都包含 CheckBox 及其 Checked
系結至 Discontinued
數據欄位的 CheckBox,兩者的唯一差異在於 ItemTemplate
's CheckBox 的 Enabled
屬性設定為 false
。
將 和 中的 ItemTemplate
CheckBox 取代為 RadioButtonList 控件,並將這兩個 RadioButtonLists ID
的屬性設定為 DiscontinuedChoice
。EditItemTemplate
接下來,指出 RadioButtonLists 應該包含兩個單選按鈕,一個標示為 “Active” 且值為 “False”,另一個標示為 “Discontinued” 且值為 “True”。 若要達成此目的,您可以直接透過宣告式語法輸入 <asp:ListItem>
中的元素,或使用ListItem
集合 編輯器 從 Designer。 圖 13 顯示ListItem
指定兩個單選按鈕選項之後的集合 編輯器。
圖 13:將 [作用中] 和 [已停止] 選項新增至 RadioButtonList (按兩下即可檢視完整大小的影像)
由於中的 ItemTemplate
RadioButtonList 不應可編輯,請將其 Enabled
屬性設定為 false
,讓 Enabled
屬性 (true
中 RadioButtonList EditItemTemplate
的預設) 。 這會將非編輯數據列中的單選按鈕設為唯讀,但會允許使用者變更已編輯數據列的 RadioButton 值。
我們仍然需要指派 RadioButtonList 控件 SelectedValue
的屬性,以便根據產品 Discontinued
的數據欄位選取適當的單選按鈕。 如同本教學課程稍早所檢查的DropDownList,此數據系結語法可以直接新增至宣告式標記,或透過 RadioButtonLists 智慧標記中的 [編輯 DataBindings] 連結。
新增兩個 RadioButtonList 並加以設定之後, Discontinued
TemplateField 的宣告式標記看起來應該像這樣:
<asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
<ItemTemplate>
<asp:RadioButtonList ID="DiscontinuedChoice" runat="server"
Enabled="False" SelectedValue='<%# Bind("Discontinued") %>'>
<asp:ListItem Value="False">Active</asp:ListItem>
<asp:ListItem Value="True">Discontinued</asp:ListItem>
</asp:RadioButtonList>
</ItemTemplate>
<EditItemTemplate>
<asp:RadioButtonList ID="DiscontinuedChoice" runat="server"
SelectedValue='<%# Bind("Discontinued") %>'>
<asp:ListItem Value="False">Active</asp:ListItem>
<asp:ListItem Value="True">Discontinued</asp:ListItem>
</asp:RadioButtonList>
</EditItemTemplate>
</asp:TemplateField>
透過這些變更,數據 Discontinued
行已從複選框清單轉換成單選按鈕組清單, (請參閱圖 14) 。 編輯產品時,會選取適當的單選按鈕,並選取其他單選按鈕並按下 [更新],即可更新產品的已停止狀態。
圖 14:已停止的 CheckBox 已由單選按鈕組取代, (按兩下即可檢視完整大小的影像)
注意
由於資料庫中的數據Discontinued
Products
行不能有NULL
值,因此我們不需要擔心在 介面中擷NULL
取資訊。 不過, Discontinued
如果數據行可能包含 NULL
我們想要將第三個單選按鈕新增至清單,並將它 Value
設定為空字串 (Value=""
) ,就像類別和供應商 DropDownLists 一樣。
摘要
雖然 BoundField 和 CheckBoxField 會自動轉譯唯讀、編輯和插入介面,但它們缺乏自定義的能力。 不過,我們通常需要自定義編輯或插入介面,或許如先前教學課程中所見, (新增驗證控件) 或自定義數據收集使用者介面 (,如本教學課程中所見) 。 您可以使用 TemplateField 自訂介面,可以在下列步驟中加總:
- 新增 TemplateField 或將現有的 BoundField 或 CheckBoxField 轉換成 TemplateField
- 視需要增強介面
- 使用雙向數據系結,將適當的數據欄位系結至新增的Web控件
除了使用內建 ASP.NET Web 控制項之外,您也可以使用自訂、編譯的伺服器控制項和使用者控制項來自定義 TemplateField 的範本。
快樂的程序設計!
關於作者
Scott Mitchell 是 1998 年以來,1998 年與 Microsoft Web 技術合作的 七篇 ASP/ASP.NET 書籍和 4GuysFromRolla.com 作者。 Scott 是獨立的顧問、訓練者和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以透過mitchell@4GuysFromRolla.com部落格連到,也可以透過其部落格來存取,網址為 http://ScottOnWriting.NET。
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應