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

ASP.NET GridView 進階技巧大全:自訂分頁、排序、匯出 Excel、滑鼠特效與空資料處理

     編輯:ASP.NET 基礎

前言

GridView 雖內建分頁與排序,但實務專案常需「自訂分頁 UI」(首頁、上一頁、下一頁、末頁、下拉選頁數)、「多欄位排序切換」、「匯出 Excel」、「列滑鼠變色/刪除確認」、「空資料顯示表頭」等進階需求。本文整理完整實作模式,可直接套用於專案。

一、自訂分頁導航列(非內建 Pager)

前端 UI 佈局

<asp:Label ID="lblTotalPages" runat="server" Text="總頁數:" />
<asp:Label ID="lblPageCount" runat="server" />
<asp:Label ID="lblCurrent" runat="server" Text="當前頁:" />
<asp:Label ID="lblPage" runat="server" Text="1" />
<asp:LinkButton ID="lnkFirst" runat="server" Text="|<" OnClick="lnkFirst_Click" />
<asp:LinkButton ID="lnkPrev" runat="server" Text="<" OnClick="lnkPrev_Click" />
<asp:LinkButton ID="lnkNext" runat="server" Text=">" OnClick="lnkNext_Click" />
<asp:LinkButton ID="lnkLast" runat="server" Text=">|" OnClick="lnkLast_Click" />
<asp:DropDownList ID="ddlPageSize" runat="server" AutoPostBack="true" OnSelectedIndexChanged="ddlPageSize_SelectedIndexChanged">
    <asp:ListItem Text="10" Value="10" />
    <asp:ListItem Text="15" Value="15" />
    <asp:ListItem Text="20" Value="20" />
    <asp:ListItem Text="30" Value="30" />
</asp:DropDownList>
<asp:Label Text="筆/頁" />

後端核心邏輯:PagedDataSource 實作

private void BindGrid(int personId)
{
    DataTable dt = GetDataByPersonId(personId); // 取得完整資料表
    if (dt.Rows.Count > 0)
    {
        PagedDataSource pds = new PagedDataSource();
        pds.DataSource = dt.DefaultView;
        pds.AllowPaging = true;
        pds.PageSize = Convert.ToInt32(ddlPageSize.SelectedValue);
        pds.CurrentPageIndex = CurrentPage - 1; // CurrentPage 為頁面屬性,預設 1

        lblPageCount.Text = pds.PageCount.ToString();
        lblPage.Text = CurrentPage.ToString();

        // 控制導航按鈕啟用狀態
        lnkFirst.Enabled = lnkPrev.Enabled = (CurrentPage > 1);
        lnkNext.Enabled = lnkLast.Enabled = (CurrentPage < pds.PageCount);

        GridView1.DataSource = pds;
        GridView1.DataBind();
    }
    else
    {
        ShowEmptyGridWithHeader(); // 空資料處理見第六節
    }
}

// 頁碼屬性儲存在 ViewState
private int CurrentPage
{
    get { return ViewState["CurrentPage"] != null ? (int)ViewState["CurrentPage"] : 1; }
    set { ViewState["CurrentPage"] = value; }
}

// 導航按鈕事件
protected void lnkFirst_Click(object sender, EventArgs e) { CurrentPage = 1; BindGrid(personId); }
protected void lnkPrev_Click(object sender, EventArgs e) { CurrentPage--; BindGrid(personId); }
protected void lnkNext_Click(object sender, EventArgs e) { CurrentPage++; BindGrid(personId); }
protected void lnkLast_Click(object sender, EventArgs e) { CurrentPage = Convert.ToInt32(lblPageCount.Text); BindGrid(personId); }
protected void ddlPageSize_SelectedIndexChanged(object sender, EventArgs e) { CurrentPage = 1; BindGrid(personId); }

二、GridView 排序實作

啟用排序屬性

<asp:GridView ID="GridView1" runat="server" AllowSorting="true" OnSorting="GridView1_Sorting" ...>

排序事件處理:儲存排序運算式與方向

protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
    string sortExpr = e.SortExpression;
    string sortDir = ViewState["SortDirection"] as string ?? "ASC";

    if (ViewState["SortExpression"] as string == sortExpr)
        sortDir = (sortDir == "ASC") ? "DESC" : "ASC"; // 同欄位切換方向

    ViewState["SortExpression"] = sortExpr;
    ViewState["SortDirection"] = sortDir;

    BindGrid(personId); // 重新繫結時套用排序
}

// 繫結前套用 DataView.Sort
private DataView GetSortedView(DataTable dt)
{
    DataView dv = dt.DefaultView;
    if (ViewState["SortExpression"] != null)
        dv.Sort = ViewState["SortExpression"] + " " + ViewState["SortDirection"];
    return dv;
}

三、內建分頁模式(簡單專案適用)

protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
    GridView1.PageIndex = e.NewPageIndex;
    BindGrid(personId); // 同一繫結方法
}

四、列選取與導向明細頁

<asp:GridView ...>
    <Columns>
        <asp:CommandField ShowSelectButton="True" SelectText="查看" />
        ...
    </Columns>
    <SelectedRowStyle BackColor="AliceBlue" ForeColor="Gray" />
</asp:GridView>

// RowDataBound 註冊客戶端點擊選取(可選)
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
        e.Row.Attributes["onclick"] = Page.ClientScript.GetPostBackClientHyperlink(GridView1, "Select$" + e.Row.RowIndex);
}

protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
    GridViewRow row = GridView1.SelectedRow;
    int id = Convert.ToInt32(row.Cells[1].Text); // 或用 DataKeys
    Response.Redirect("Detail.aspx?ID=" + id);
}

五、列滑鼠懸停變色、刪除確認、條件格式

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // 滑鼠進入/離開變色
        e.Row.Attributes["onmouseover"] = "this.style.backgroundColor='#00A9FF';";
        e.Row.Attributes["onmouseout"] = "this.style.backgroundColor='#E6F5FA';";

        // 刪除按鈕確認對話框(假設第 2 儲存格為 ImageButton)
        ImageButton btnDel = (ImageButton)e.Row.Cells[2].FindControl("IBtnDelete");
        if (btnDel != null)
            btnDel.Attributes["onclick"] = "return confirm('確定刪除「" + e.Row.Cells[0].Text + "」嗎?');";

        // 條件格式:特定值標紅
        if (e.Row.Cells[1].Text == "444")
            e.Row.Cells[1].BackColor = System.Drawing.Color.Red;
    }
}

六、空資料顯示表頭與提示訊息

private void ShowEmptyGridWithHeader()
{
    DataTable dt = GetDataByPersonId(personId); // 可能為空
    if (dt.Rows.Count == 0)
    {
        dt.Rows.Add(dt.NewRow()); // 加入空白行以產生表頭
        GridView1.DataSource = dt;
        GridView1.DataBind();

        // 合併儲存格顯示提示
        int colCount = GridView1.Rows[0].Cells.Count;
        GridView1.Rows[0].Cells.Clear();
        GridView1.Rows[0].Cells.Add(new TableCell());
        GridView1.Rows[0].Cells[0].ColumnSpan = colCount;
        GridView1.Rows[0].Cells[0].Text = "查無資料";
        GridView1.Rows[0].Cells[0].Style.Value = "text-align:center; color:gray;";
    }
    else
    {
        GridView1.DataSource = dt;
        GridView1.DataBind();
    }
}

// 或直接使用 GridView 屬性(僅顯示文字,無表頭)
// GridView1.EmptyDataText = "查無資料";

七、匯出 Excel(需 EnableEventValidation="false")

public override void VerifyRenderingInServerForm(Control control) { } // 必須覆寫

protected void btnExport_Click(object sender, EventArgs e)
{
    Response.Clear();
    Response.Buffer = true;
    Response.Charset = "UTF-8";
    Response.AppendHeader("Content-Disposition", "attachment;filename=Export.xls");
    Response.ContentEncoding = System.Text.Encoding.UTF8; // 避免中文亂碼
    Response.ContentType = "application/ms-excel";

    using (StringWriter sw = new StringWriter())
    using (HtmlTextWriter htw = new HtmlTextWriter(sw))
    {
        GridView1.RenderControl(htw);
        Response.Output.Write(sw.ToString());
    }
    Response.Flush();
    Response.End();
}
注意:匯出前請暫時關閉分頁(GridView1.AllowPaging = false; BindGrid();),否則僅匯出當頁資料。

八、ToolTip 滑鼠顯示詳細資訊(JavaScript + RowDataBound)

<script type="text/javascript">
    var tooltip = document.createElement('div');
    tooltip.id = 'gvTooltip';
    tooltip.style.cssText = 'position:absolute;display:none;background:#fff;border:1px solid #333;padding:8px;z-index:999;box-shadow:2px 2px 6px rgba(0,0,0,.2);';
    document.body.appendChild(tooltip);

    function showTooltip(id, detail) {
        tooltip.innerHTML = 'ID: ' + id + '
詳情: ' + detail; tooltip.style.display = 'block'; tooltip.style.left = (event.clientX + 10) + 'px'; tooltip.style.top = (event.clientY + 10) + 'px'; } function hideTooltip() { tooltip.style.display = 'none'; } </script> protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { string id = e.Row.Cells[0].Text; string detail = e.Row.Cells[1].Text; e.Row.Attributes["onmouseover"] = $"showTooltip('{id}', '{detail}');"; e.Row.Attributes["onmouseout"] = "hideTooltip();"; } }

九、內建編輯/更新/刪除/取消事件模板

protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
    GridView1.EditIndex = e.NewEditIndex;
    BindGrid(personId);
}

protected void GridView1_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
    GridView1.EditIndex = -1;
    BindGrid(personId);
}

protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    GridViewRow row = GridView1.Rows[e.RowIndex];
    int id = Convert.ToInt32(GridView1.DataKeys[e.RowIndex].Value);
    string newVal = ((TextBox)row.Cells[1].Controls[0]).Text.Trim();
    // UpdateDatabase(id, newVal);
    GridView1.EditIndex = -1;
    BindGrid(personId);
}

protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
    int id = Convert.ToInt32(GridView1.DataKeys[e.RowIndex].Value);
    // DeleteDatabase(id);
    BindGrid(personId);
}

總結與建議

  • 自訂分頁靈活度高,適合需「每頁筆數可調、跳頁輸入」的後台管理。
  • 排序狀態儲存在 ViewState,跨頁保持一致。
  • 匯出 Excel採用 RenderControl 輸出 HTML 表格,Excel 可直接開啟;大量資料建議改用 EPPlus/ClosedXML 產生真正 .xlsx。
  • 空資料處理合併儲存格法可保留表頭,使用者體驗優於 EmptyDataText。
  • 客戶端特效(滑鼠變色、Tooltip)純前端實作,不增加伺服器負擔。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved