共用方式為


於刪除時新增用戶端確認 (C#)

斯科特·米切爾

下載 PDF

在我們目前所建立的介面中,使用者可能會在想點擊 [編輯] 按鈕時不小心點擊 [刪除] 按鈕從而刪除數據。 在本教學課程中,我們將新增按兩下 [刪除] 按鈕時出現的用戶端確認對話方塊。

簡介

在過去數個教學課程中,我們已瞭解如何使用應用程式架構、ObjectDataSource 和數據 Web 控制項,以提供插入、編輯和刪除功能。 到目前為止,我們所檢查的刪除介面是由〔刪除〕按鈕組成,當按一下時,會導致 postback 並叫用 ObjectDataSource 的 Delete() 方法。 方法 Delete() 接著會從商業規則層叫用已設定的方法,該層會將呼叫向下傳播至數據存取層,並將實際 DELETE 語句發出至資料庫。

雖然此使用者介面可讓訪客透過 GridView、DetailsView 或 FormView 控件刪除記錄,但是當使用者按兩下 [刪除] 按鈕時,它就缺少任何確認。 如果使用者在想要按兩下 [編輯] 時不小心按兩下 [刪除] 按鈕,則會改為刪除要更新的記錄。 為了協助避免這種情況,在本教學課程中,我們將新增按兩下 [刪除] 按鈕時出現的用戶端確認對話方塊。

JavaScript confirm(string) 函式會將其字串輸入參數顯示為具有兩個按鈕的強制回應對話方塊內的文字 - OK 和 Cancel (請參閱圖 1)。 此 confirm(string) 函式會根據按鍵傳回布林值(true如果使用者按兩下[確定],以及 false 按兩下 [取消] 。

JavaScript confirm(string) 方法顯示模態窗口,標示為 Client-Side 的提示框

圖 1:JavaScript confirm(string) 方法會顯示模態對話框,Client-Side 訊息框

在表單提交期間,如果用戶端事件處理程式傳回的值為false,則會取消表單提交。 使用這項功能,我們可以讓 [刪除] 按鈕的用戶端 onclick 事件處理程式傳回 對 confirm("Are you sure you want to delete this product?")的呼叫值。 如果使用者按兩下 [取消], confirm(string) 將會傳回 false,因而導致表單提交取消。 沒有回傳時,點擊 [刪除] 按鈕的產品不會被刪除。 不過,如果使用者在確認對話框中按兩下 [確定],則回傳將會繼續不減,且將會刪除產品。 如需這項技術的詳細資訊,請參閱 使用JavaScript s confirm() 方法來控制表單提交

當使用範本時,新增必要的用戶端腳本會和使用 CommandField 稍有不同。 因此,在本教學課程中,我們將探討 FormView 和 GridView 範例。

備註

使用用戶端確認技術,例如本教學課程中所討論的確認技術,假設您的使用者正在瀏覽支援 JavaScript 的瀏覽器,並啟用 JavaScript。 如果任何一項假設對特定使用者而言不成立,點選 [刪除] 按鈕後會立即造成回傳(未顯示確認消息框)。

步驟 1:建立支持刪除的 FormView

首先,將 FormView 新增至資料夾中的頁面ConfirmationOnDelete.aspx,並將它系結至EditInsertDelete新的 ObjectDataSource,以透過 ProductsBLL 類別 s GetProducts() 方法提取產品資訊。 同時設定 ObjectDataSource,讓 ProductsBLL 類別的 DeleteProduct(productID) 方法對應至 ObjectDataSource s Delete() 方法;請確定 INSERT 和 UPDATE 索引卷標下拉式清單已設定為 [無]。 最後,勾選 FormView 智慧標記中的 [啟用分頁] 複選框。

在這些步驟之後,新的 ObjectDataSource 宣告式標記看起來會如下所示:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    DeleteMethod="DeleteProduct" OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProducts" TypeName="ProductsBLL">
    <DeleteParameters>
        <asp:Parameter Name="productID" Type="Int32" />
    </DeleteParameters>
</asp:ObjectDataSource>

如同過去未使用樂觀並行控制的範例,請花點時間清除 ObjectDataSource 的 OldValuesParameterFormatString 屬性。

由於它已系結至僅支持刪除的 ObjectDataSource 控件,所以 FormView 只 ItemTemplate 提供 [刪除] 按鈕,缺少 [新增] 和 [更新] 按鈕。 不過,FormView 的宣告式標記包含多餘的 EditItemTemplateInsertItemTemplate,可加以移除。 請花點時間自定義 ItemTemplate ,以便只顯示產品數據欄位的子集。 我已將我的設定為在 <h3> 標題中顯示產品名稱,該標題位於其供應商和類別名稱之上(以及 [刪除] 按鈕)。

<asp:FormView ID="FormView1" AllowPaging="True" DataKeyNames="ProductID"
    DataSourceID="ObjectDataSource1" runat="server">
    <ItemTemplate>
        <h3><i><%# Eval("ProductName") %></i></h3>
        <b>Category:</b>
        <asp:Label ID="CategoryNameLabel" runat="server"
            Text='<%# Eval("CategoryName") %>'>
        </asp:Label><br />
        <b>Supplier:</b>
        <asp:Label ID="SupplierNameLabel" runat="server"
            Text='<%# Eval("SupplierName") %>'>
        </asp:Label><br />
        <asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False"
            CommandName="Delete" Text="Delete">
        </asp:LinkButton>
    </ItemTemplate>
</asp:FormView>

透過這些變更,我們有一個功能完整的網頁,可讓使用者一次切換一個產品,只要按兩下 [刪除] 按鈕即可刪除產品。 圖 2 顯示透過瀏覽器檢視到目前為止進度的螢幕快照。

FormView 會顯示單一產品的相關信息

圖 2:FormView 顯示單一產品的相關信息(按兩下以檢視完整大小的影像

步驟 2:從 [刪除按鈕] Client-Side 的 onclick 事件中呼叫 confirm(字串)函式

建立 FormView 之後,最後一個步驟是設定 [刪除] 按鈕,讓訪客按兩下該按鈕時,就會叫用 JavaScript confirm(string) 函式。 將用戶端腳本新增至 Button、LinkButton 或 ImageButton s 用戶端 onclick 事件,可透過 使用 OnClientClick property來完成,這是 ASP.NET 2.0 的新功能。 由於我們想要傳回函式的值 confirm(string) ,因此只要將此屬性設定為: return confirm('Are you certain that you want to delete this product?');

在此變更之後,Delete LinkButton 的宣告式語法看起來應該像這樣:

<asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False"
    CommandName="Delete" Text="Delete"
    OnClientClick="return confirm('Are you certain you want to delete this product?');">
</asp:LinkButton>

就這麼簡單! 圖 3 顯示此確認運作時的螢幕快照。 按兩下 [刪除] 按鈕會顯示 [確認] 對話框。 如果使用者按兩下 [取消],則會取消回傳,且不會刪除產品。 不過,如果使用者按兩下 [確定],則會繼續回傳,並叫用 ObjectDataSource s Delete() 方法,最終刪除資料庫記錄。

備註

傳入 JavaScript 函式的 confirm(string) 字串是以單引號分隔(而非引號)。 在 JavaScript 中,可以使用任一字元來分隔字串。 我們在這裡使用單引號,讓傳入 confirm(string) 之字串的分隔符不會與屬性值所使用的 OnClientClick 分隔符產生模棱兩可。

按兩下 [刪除] 按鈕時,現在會顯示確認

圖 3:按兩下 [刪除] 按鈕時,現在會顯示確認 (按兩下以檢視完整大小的影像

步驟 3:在 CommandField 中設定刪除按鈕的 OnClientClick 屬性

直接在範本中使用 Button、LinkButton 或 ImageButton 時,只需設定其 OnClientClick 屬性,使其回傳 JavaScript confirm(string) 函式的結果,即可將確認對話框與它建立關聯。 不過,CommandField 將 Delete 按鈕欄位新增到 GridView 或 DetailsView,但它沒有可以用宣告方式設定的 OnClientClick 屬性。 相反地,我們必須以程式設計方式參考 GridView 或 DetailsView 中適當的 DataBound 事件處理程式中的 [刪除] 按鈕,然後在該處設定其 OnClientClick 屬性。

備註

在適當的OnClientClick事件處理程式中設定 [刪除] 按鈕的DataBound屬性時,我們可以存取已系結至目前記錄的數據。 這表示我們可以延伸確認訊息以包含特定記錄的詳細數據,例如「您確定要刪除 Chai 產品嗎?使用數據系結語法的範本中也可以進行這類自定義。

若要練習在 CommandField 中設定 OnClientClick [刪除] 按鈕的屬性,讓我們將 GridView 新增至頁面。 將此 GridView 設定為使用 FormView 所使用的相同 ObjectDataSource 控制件。 此外,也會限制 GridView s BoundFields 只包含產品名稱、類別和供應商。 最後,核取 GridView 智慧標記中的 [啟用刪除] 複選框。 這會將 CommandField 新增至 GridView s Columns 集合,並將其 ShowDeleteButton 屬性設定為 true

進行這些變更之後,您的 GridView 宣告式標記看起來應該如下所示:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" />
        <asp:BoundField DataField="ProductName" HeaderText="Product"
            SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category" ReadOnly="True"
            SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName" HeaderText="Supplier" ReadOnly="True"
            SortExpression="SupplierName" />
    </Columns>
</asp:GridView>

CommandField 包含可從 GridView 事件處理程式 RowDataBound 以程式設計方式存取的單一 Delete LinkButton 實例。 參考之後,我們可以據以設定其 OnClientClick 屬性。 使用下列程式代碼建立 RowDataBound 事件的事件處理程式:

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // reference the Delete LinkButton
        LinkButton db = (LinkButton)e.Row.Cells[0].Controls[0];

        // Get information about the product bound to the row
        Northwind.ProductsRow product =
            (Northwind.ProductsRow) ((System.Data.DataRowView) e.Row.DataItem).Row;

        db.OnClientClick = string.Format(
            "return confirm('Are you certain you want to delete the {0} product?');",
            product.ProductName.Replace("'", @"\'"));
    }
}

此事件處理程式可與包含 [刪除] 按鈕的數據列一起運作,並透過程式碼先引用 [刪除] 按鈕。 一般而言,請使用下列模式:

ButtonType obj = (ButtonType) e.Row.Cells[commandFieldIndex].Controls[controlIndex];

ButtonType 是 CommandField - Button、LinkButton 或 ImageButton 所使用的按鈕類型。 根據預設,CommandField 會使用 LinkButtons,但可以透過 CommandField s ButtonType property自定義。 commandFieldIndex 是 GridView 集合Columns中 CommandField 的序數字索引,而 controlIndex 則是 CommandField 集合Controls中 [刪除] 按鈕的索引。 controlIndex 值取決於與 CommandField 中其他按鈕相對的按鈕位置。 例如,如果 CommandField 中顯示的唯一按鈕是 [刪除] 按鈕,請使用索引 0。 不過,如果 [編輯] 按鈕位於 [刪除] 按鈕之前,請使用索引 2。 使用 2 索引的原因是 CommandField 會在 [刪除] 按鈕之前新增兩個控件:[編輯] 按鈕和用來在 [編輯] 和 [刪除] 按鈕之間新增一些空格的 LiteralControl。

針對我們的特定範例,CommandField 使用 LinkButtons,且作為最左邊的欄位,其 commandFieldIndex 為 0。 由於 CommandField 中除了 [刪除] 按鈕外沒有其他按鈕,因此我們使用 controlIndex 的值為 0。

在參考 CommandField 中的 [刪除] 按鈕之後,我們會接著擷取系結至目前 GridView 數據列之產品的相關信息。 最後,我們會將 [刪除] 按鈕 s OnClientClick 屬性設定為適當的 JavaScript,其中包含產品名稱。 因為傳入 confirm(string) 函式的 JavaScript 字串使用單引號分隔,因此我們必須跳脫出現在產品名稱中的任何單引號。 特別是,產品名稱中的任何單引號都會以「\'」轉義。

完成這些變更后,按兩下 GridView 中的 [刪除] 按鈕會顯示自訂的確認對話框(請參閱圖 4)。 如同 FormView 中的確認消息框,如果使用者按兩下 [取消回傳] 就會取消,因而防止刪除。

備註

這項技術也可以用來以程式設計方式存取 DetailsView 中 CommandField 中的 [刪除] 按鈕。 不過,針對 DetailsView,您會建立 DataBound 事件的事件處理程式,因為 DetailsView 沒有 RowDataBound 事件。

按兩下 GridView s Delete 按鈕會顯示自定義的確認對話方塊

圖 4:按兩下 GridView s Delete 按鈕會顯示自訂確認對話框 (按兩下以檢視完整大小的影像

使用模板字段

CommandField 的其中一個缺點是其按鈕必須透過索引進行存取,而且產生的對象必須轉換成適當的按鈕類型(Button、LinkButton 或 ImageButton)。 使用「魔數」和硬編碼類型會導致一些問題,這些問題在運行時才會被發現。 例如,如果您或其他開發人員在未來某個時間點將新的按鈕新增至 CommandField(例如編輯按鈕)或變更 ButtonType 屬性,則現有的程式代碼仍會編譯而不會發生錯誤,但瀏覽頁面可能會造成例外狀況或非預期的行為,視程式代碼的撰寫方式和所做的變更而定。

替代方法是將 GridView 和 DetailsView s CommandFields 轉換成 TemplateFields。 這會產生 TemplateField,其中包含 ItemTemplate CommandField 中每個按鈕的 LinkButton (或 Button 或 ImageButton)。 您可以使用下列模式,以宣告方式指派這些按鈕 OnClientClick 屬性,如我們在 FormView 中所見,或者可以使用下列模式,以程式設計方式在適當的 DataBound 事件處理程式中存取:

ButtonType obj = (ButtonType) e.Row.FindControl("controlID");

其中 controlID 是按鈕 s ID 屬性的值。 雖然此模式仍需要硬編碼類型來進行轉換,但會移除索引的需求,讓版面配置能夠變更,且不會造成運行時錯誤。

總結

JavaScript confirm(string) 函式是控制表單提交工作流程的常用技術。 執行時,函式會顯示包含兩個按鈕的強制回應用戶端對話框:[確定] 和 [取消]。 如果使用者按下 [確定],函式會 confirm(string)true回 ;按兩下 [取消] 會傳 false回 。 這項功能結合瀏覽器的行為,即如果提交過程中的事件處理程式返回false,則取消表單提交,可以在刪除記錄時顯示確認訊息框。

函數confirm(string)可以透過控制項的onclick屬性與按鈕 Web 控制項的用戶端OnClientClick事件處理程式產生關聯。 使用範本中的 [刪除] 按鈕時,無論是在其中一個 FormView 範本中,還是在 DetailsView 或 GridView 的 TemplateField 中,都可以以宣告方式或以程式設計方式設定此屬性,如本教學課程中所見。

快樂的程序設計!

關於作者

斯科特·米切爾,七本 ASP/ASP.NET 書籍和 4GuysFromRolla.com 創始人的作者,自1998年以來一直與Microsoft Web 技術合作。 斯科特擔任獨立顧問、教練和作家。 他的最新書是 山姆斯教自己 ASP.NET 2.0 在24小時內完成。 他可以聯絡 mitchell@4GuysFromRolla.com。