首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET 2.0 資料教程:為 GridView 新增 CheckBox 列實現批次刪除 (TemplateField + 按鈕觸發)

     編輯:關於ASP.NET

GridView 內建刪除僅支援單列。本文示範加入 CheckBox 列 (TemplateField),配合「刪除選取項目」按鈕,實現批次刪除功能。涵蓋分頁情境下跨頁選取狀態保持、全選/反選、批次執行與交易處理。

GridView 定義 CheckBox 列

<asp:GridView ID="gvProducts" runat="server" 
    DataSourceID="odsProducts" 
    AutoGenerateColumns="False"
    DataKeyNames="ProductID"
    AllowPaging="True" PageSize="10"
    OnRowDataBound="gvProducts_RowDataBound"
    OnPreRender="gvProducts_PreRender">

    <Columns>
        <asp:TemplateField HeaderText="選取">
            <HeaderTemplate>
                <asp:CheckBox ID="cbSelectAll" runat="server" 
                    onclick="toggleSelectAll(this)" />
            </HeaderTemplate>
            <ItemTemplate>
                <asp:CheckBox ID="cbSelect" runat="server" />
            </ItemTemplate>
        </asp:TemplateField>

        <asp:BoundField DataField="ProductID" HeaderText="ID" ReadOnly="True" />
        <asp:BoundField DataField="ProductName" HeaderText="產品名稱" />
        <asp:BoundField DataField="UnitPrice" HeaderText="單價" DataFormatString="{0:C2}" HtmlEncode="False" />
        <asp:BoundField DataField="UnitsInStock" HeaderText="庫存" />
        
        <asp:CommandField ShowEditButton="True" ShowDeleteButton="True" />
    </Columns>
</asp:GridView>

<asp:Button ID="btnDeleteSelected" runat="server" Text="刪除選取項目" 
    OnClick="btnDeleteSelected_Click" OnClientClick="return confirm('確定刪除選取的產品?')" />
<asp:Label ID="lblStatus" runat="server" ForeColor="Green" />

JavaScript 全選/反選

<script type="text/javascript">
    function toggleSelectAll(headerCheckbox) {
        var grid = document.getElementById('<%= gvProducts.ClientID %>');
        var checkboxes = grid.getElementsByTagName('input');
        for (var i = 0; i < checkboxes.length; i++) {
            if (checkboxes[i].type == 'checkbox' && checkboxes[i].id != headerCheckbox.id) {
                checkboxes[i].checked = headerCheckbox.checked;
            }
        }
    }
</script>

跨頁選取狀態保持:ViewState 儲存選取的 ProductID 集合

private List SelectedProductIDs
{
    get
    {
        if (ViewState["SelectedProductIDs"] == null)
            ViewState["SelectedProductIDs"] = new List();
        return (List)ViewState["SelectedProductIDs"];
    }
    set { ViewState["SelectedProductIDs"] = value; }
}

protected void gvProducts_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        CheckBox cb = (CheckBox)e.Row.FindControl("cbSelect");
        int productID = (int)gvProducts.DataKeys[e.Row.RowIndex].Value;
        
        // 還原選取狀態
        cb.Checked = SelectedProductIDs.Contains(productID);
        
        // 附加 ProductID 以便客戶端/伺服端識別
        cb.Attributes["data-product-id"] = productID.ToString();
    }
}

protected void gvProducts_PreRender(object sender, EventArgs e)
{
    // 頁面渲染前,根據目前頁面的 CheckBox 狀態更新 ViewState
    foreach (GridViewRow row in gvProducts.Rows)
    {
        CheckBox cb = (CheckBox)row.FindControl("cbSelect");
        int productID = (int)gvProducts.DataKeys[row.RowIndex].Value;
        
        if (cb.Checked)
        {
            if (!SelectedProductIDs.Contains(productID))
                SelectedProductIDs.Add(productID);
        }
        else
        {
            SelectedProductIDs.Remove(productID);
        }
    }
}

批次刪除執行:交易包裝、逐一呼叫 BLL Delete

protected void btnDeleteSelected_Click(object sender, EventArgs e)
{
    if (SelectedProductIDs.Count == 0)
    {
        lblStatus.Text = "請先選取要刪除的產品";
        return;
    }

    int successCount = 0;
    var bll = new BLL.ProductsBLL();
    
    // 使用 TransactionScope 確保原子性 (需 System.Transactions 參考)
    using (var scope = new System.Transactions.TransactionScope())
    {
        try
        {
            foreach (int id in SelectedProductIDs)
            {
                // 檢查業務規則:如有訂單明細不可刪除
                if (bll.CanDeleteProduct(id))
                {
                    bll.DeleteProduct(id);
                    successCount++;
                }
            }
            scope.Complete();
        }
        catch (Exception ex)
        {
            lblStatus.Text = "刪除失敗:" + ex.Message;
            return;
        }
    }

    SelectedProductIDs.Clear();
    gvProducts.DataBind();
    lblStatus.Text = $"成功刪除 {successCount} 筆產品";
}

ProductsBLL 批次刪除優化 (選用)

// 使用 TableAdapter 批次更新 (需 DAL 支援)
public void DeleteProductsBatch(List productIDs)
{
    // 方案 A: 單一 SQL IN 子句 (效能最佳)
    string ids = string.Join(",", productIDs);
    string sql = $"DELETE FROM Products WHERE ProductID IN ({ids}) AND ProductID NOT IN (SELECT ProductID FROM Order_Details)";
    _adapter.ExecuteNonQuery(sql);

    // 方案 B: TableAdapter 批次更新 (需設定 BatchSize)
    // _adapter.UpdateBatchSize = 100;
    // foreach (id) _adapter.Delete(id);
    // _adapter.Update(dataTable);
}

分頁情境完整流程圖解

  1. 使用者勾選第 1 頁 3 項 → PreRender 存入 ViewState
  2. 翻至第 2 頁 → RowDataBound 還原 ViewState 狀態 → 勾選 2 項
  3. 點擊「刪除選取」 → btnDeleteSelected_Click 讀取 ViewState 共 5 個 ID → 批次刪除
  4. 刪除完成 → 清空 ViewState → DataBind 重新整理

進階:Client-Side 狀態管理 (減少 Postback)

使用 HiddenField 儲存 JSON 陣列,JavaScript 維護選取集合,Postback 時一次提交:

<asp:HiddenField ID="hfSelectedIDs" runat="server" />

<script>
    var selected = [];
    function toggleRow(cb, id) {
        if (cb.checked) selected.push(id); else selected = selected.filter(x => x != id);
        document.getElementById('<%= hfSelectedIDs.ClientID %>').value = JSON.stringify(selected);
    }
    // 全選邏輯類似
</script>

protected void btnDeleteSelected_Click(object sender, EventArgs e)
{
    var ids = Newtonsoft.Json.JsonConvert.DeserializeObject>(hfSelectedIDs.Value);
    // ... 批次刪除
    hfSelectedIDs.Value = "[]";
}

結語

GridView 批次操作核心在於:TemplateField CheckBox、跨頁狀態保持 (ViewState/HiddenField)、全選 JavaScript、交易包裝批次執行。此模式可擴充至批次編輯、批次匯出、批次狀態變更等情境。現代專案建議採用客戶端狀態管理 + Web API 批次端點,減少 ViewState 體積與 Postback 開銷。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved