Views: 24
接續學員資料管理Member/Manage.aspx,這篇要做按下編輯後,彈出新視窗編輯
編輯資料頁的幾種常見方式說明
在 ASP.NET WebForm 或其他網頁應用中,針對「編輯資料」的操作方式大致可以分為以下幾類,每種有不同的適用場景與技術手法:
1. 使用 iFrame 開啟編輯視窗(嵌入頁面)
- 做法:在主頁面內開啟一個彈出區塊(或新區塊),透過
<iframe>
載入編輯用的頁面。 - 優點:
- 隔離主畫面與編輯頁,互不干擾。
- 簡單快速,不需重構畫面。
- 缺點:
- 體驗略顯老舊,無法完全控制
iframe
內的互動與樣式。 - 和主頁面溝通需額外透過 JavaScript。
- 體驗略顯老舊,無法完全控制
- 適合場景:快速套用既有頁面、想省事的舊系統維護。
補充說明: Ifram是在原有WEB頁面內再崁入另一個葉面
2. 開新視窗或分頁(獨立編輯頁)
- 做法:點選編輯按鈕後,透過
Response.Redirect()
或 JavaScript 的window.open()
開新頁面,編輯完後點儲存並關閉頁面。 - 優點:
- 編輯頁獨立清楚,適合複雜資料。
- 前後流程簡單直覺。
- 缺點:
- 需注意使用者操作流程與視窗關閉時機。
- 無法直接即時回傳主頁更新,通常需靠
refresh
。
- 適合場景:後台系統、複雜編輯表單、表單需要多欄位或分頁的情境。
3. 編輯與清單同一頁(使用 Panel 隱藏/顯示)
- 做法:主頁面下方或右側內建編輯區塊(如
Panel
),平時隱藏,點選「編輯」時載入該筆資料顯示出來。 - 優點:
- 使用者不需跳頁,體驗流暢。
- 簡單控制,易於資料同步。
- 缺點:
- 畫面需預留空間。
- 當資料過多或多欄位時畫面會變擁擠。
- 適合場景:小型表單、資料量少、希望「單頁操作」的情況。
4. 使用 Modal(彈跳視窗)編輯
- 做法:點選「編輯」後,顯示 Bootstrap 或 jQuery UI 的 Modal 彈窗進行編輯。
- 優點:
- 使用者體驗佳,現代化介面。
- 適合單一欄位或簡單表單編輯。
- 缺點:
- WebForm 實作較複雜,不像 MVC 那樣有原生支援。
- 控制項的生命週期與事件管理難度較高。
- 適合場景:較新式或自定義的 UI、搭配 jQuery 或 Bootstrap 的專案。
編輯的作法整理
方法 | 頁面跳轉 | 使用體驗 | 適合資料量 | 備註 |
---|---|---|---|---|
iFrame | 否 | 中 | 中小 | 維護舊系統時可用 |
開新視窗 | 是 | 中上 | 中大 | 傳統常見方式 |
同頁 Panel 切換 | 否 | 高 | 小 | 單頁應用適合 |
Modal 彈出編輯視窗 | 否 | 高 | 小中 | 現代介面,WebForm需額外處理事件控制 |
個人生涯上在Webform遇到的頻率
開新視窗 >>>> Panel切換 > iFrame>>>>Modal
接下來的教學以最常見的開新視窗做說明。
編輯報名資料- 開新視窗
實際上做出來流程如上圖
開新視窗有兩個重點
- 點下去會開新視窗(這個比較簡單)
- 關掉視窗會觸發列表更新
要做的工作
- 設計新視窗用Master Page的
Dialog.Master
- 設計編輯頁
Member/Edit.aspx
- 管理頁加入開新視窗的指令
- 管理頁加入關閉視窗會更新列表的指令
新增Dialog.Master
對著專案中的Admin資料夾按右鍵 > 加入 >新增項目
選擇 使用主版頁面的Web Form ,名稱輸入Dialog.Master 按下新增
編輯Dialog.Master
Dialog.Master
跟Admin.Master
差別在於沒有Navbar跟footer,所以可以直接拷貝Admin.Master
的內容後貼上,然後刪除Navbar跟footer
弄完的結果如下
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Dialog.master.cs" Inherits="PartyRegister.Admin.Dialog" %>
<!DOCTYPE html>
<html lang="zh">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%: Page.Title %></title>
<asp:PlaceHolder runat="server">
<%: Scripts.Render("~/bundles/modernizr") %>
</asp:PlaceHolder>
<webopt:bundlereference runat="server" path="~/Content/css" />
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
</head>
<body>
<form runat="server">
<asp:ScriptManager runat="server">
<Scripts>
<%--To learn more about bundling scripts in ScriptManager see https://go.microsoft.com/fwlink/?LinkID=301884 --%>
<%--Framework Scripts--%>
<asp:ScriptReference Name="MsAjaxBundle" />
<asp:ScriptReference Name="jquery" />
<asp:ScriptReference Name="WebForms.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebForms.js" />
<asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebUIValidation.js" />
<asp:ScriptReference Name="MenuStandards.js" Assembly="System.Web" Path="~/Scripts/WebForms/MenuStandards.js" />
<asp:ScriptReference Name="GridView.js" Assembly="System.Web" Path="~/Scripts/WebForms/GridView.js" />
<asp:ScriptReference Name="DetailsView.js" Assembly="System.Web" Path="~/Scripts/WebForms/DetailsView.js" />
<asp:ScriptReference Name="TreeView.js" Assembly="System.Web" Path="~/Scripts/WebForms/TreeView.js" />
<asp:ScriptReference Name="WebParts.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebParts.js" />
<asp:ScriptReference Name="Focus.js" Assembly="System.Web" Path="~/Scripts/WebForms/Focus.js" />
<asp:ScriptReference Name="WebFormsBundle" />
<%--Site Scripts--%>
</Scripts>
</asp:ScriptManager>
<div class="container body-content">
<asp:ContentPlaceHolder ID="MainContent" runat="server">
</asp:ContentPlaceHolder>
</div>
</form>
<asp:PlaceHolder runat="server">
<%: Scripts.Render("~/Scripts/bootstrap.js") %>
</asp:PlaceHolder>
</body>
</html>
編輯Dialog.Master.cs
因為這是給後台用的,所以同樣要加入權限驗證
如果覺得權限驗證在開發時候導致每次都要登入令人煩躁,可以之後再加入(不過務必要記得加)
using System;
namespace PartyRegister.Admin
{
public partial class Dialog : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
//檢查是否登入
if (Session["User"] == null)
{
//導向登入頁(或導向首頁)
Response.Redirect("~/Admin/Login.aspx");
}
}
}
}
新增Edit.aspx
Member資料夾按右鍵 > 加入> 使用主版頁面的Web Form
檔名輸入Edit.aspx
接著Master Page選擇
選Admin > Dialog.Master
> 確定
新增Edit.aspx
完成
Edit頁的內容
Edit.aspx
這邊的內容其實跟先前活動報名的Regist.aspx
幾乎一樣,差別在於送出的按鈕變成更新的按鈕,然後多一個取消的按鈕
<%@ Page Title="" Language="C#" MasterPageFile="~/Admin/Dialog.Master" AutoEventWireup="true" CodeBehind="Edit.aspx.cs" Inherits="PartyRegister.Admin.Member.Edit" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<asp:Label ID="lbName" runat="server" Text="姓名"></asp:Label>
<asp:TextBox ID="tbName" runat="server" required></asp:TextBox>
<br />
<br />
<asp:Label runat="server" ID="lbGender" Text="性別"></asp:Label>
<asp:RadioButtonList runat="server" ID="rbGender" RepeatDirection="Horizontal">
<asp:ListItem Text="男" Value="1"></asp:ListItem>
<asp:ListItem Text="女" Value="2"></asp:ListItem>
<asp:ListItem Text="其他" Value="3"></asp:ListItem>
</asp:RadioButtonList>
<asp:RequiredFieldValidator
ID="rfvGender"
runat="server"
ControlToValidate="rbGender"
InitialValue=""
ErrorMessage="請選擇性別"
ForeColor="Red"
Display="Dynamic" />
<br />
<asp:Label ID="lbPhone" runat="server" Text="聯絡電話"></asp:Label>
<asp:TextBox ID="tbPhone" runat="server" required></asp:TextBox>
<br />
<asp:Label ID="lbBirthday" runat="server" Text="生日"></asp:Label>
<asp:TextBox ID="tbBirthday" runat="server" required></asp:TextBox>
<br />
<asp:Label ID="lbROCID" runat="server" Text="身分證字號"></asp:Label>
<asp:TextBox ID="tbROCID" runat="server" required></asp:TextBox>
<br />
<asp:Label ID="lbEmail" runat="server" Text="信箱"></asp:Label>
<asp:TextBox ID="tbEmail" runat="server" required></asp:TextBox>
<br />
<br />
<asp:Label runat="server" ID="lbFood" Text="飲食"></asp:Label>
<asp:RadioButtonList runat="server" ID="rbFood" RepeatDirection="Horizontal">
<asp:ListItem Text="葷" Value="1"></asp:ListItem>
<asp:ListItem Text="素" Value="2"></asp:ListItem>
<asp:ListItem Text="其他" Value="3"></asp:ListItem>
</asp:RadioButtonList>
<asp:RequiredFieldValidator
ID="rfvFood"
runat="server"
ControlToValidate="rbFood"
InitialValue=""
ErrorMessage="請選擇飲食"
ForeColor="Red"
Display="Dynamic" />
<br />
<asp:Label runat="server" ID="lbEventId" Text="活動場次"></asp:Label>
<asp:RadioButtonList runat="server" ID="rbEventId" RepeatDirection="Horizontal">
<asp:ListItem Text="1月份" Value="1"></asp:ListItem>
<asp:ListItem Text="2月份" Value="2"></asp:ListItem>
<asp:ListItem Text="3月份" Value="3"></asp:ListItem>
</asp:RadioButtonList>
<asp:RequiredFieldValidator
ID="rfvEventId"
runat="server"
ControlToValidate="rbFood"
InitialValue=""
ErrorMessage="請選擇活動場次"
ForeColor="Red"
Display="Dynamic" />
<br />
<asp:Label runat="server" ID="lbErrorMsg" ForeColor="red"></asp:Label>
<br />
<asp:Button ID="btnSubmit" CssClass="btn btn-primary" Text="更新" runat="server" OnClick="btnSubmit_OnClick" />
<asp:Button ID="btnCancel" CssClass="btn btn-secondary" Text="取消" runat="server" OnClick="btnCancel_OnClick" />
</asp:Content>
Edit.aspx.cs
這邊的內容就跟Regedit.aspx.cs不同了,具體上Key Point有下列幾個大項
Page_Load()
頁面開啟時,要讀取網址帶入的id (例如Edit.aspx?id=6
,會取得6),在網址列帶入ID的做法是透過Get傳遞資訊,另一種常見的作法是Post,不過Post要在新視窗做比較困難,普遍是在Ajax配合Modal進行。BindData()
:id讀取後將對應的資料從資料庫取出,並寫入頁面的欄位中。btnSubmit_OnClick()
更新存檔時:將頁面的資料讀取後更新至資料庫(這邊我略過邏輯規則檢查),並且關閉與呼叫Manage.aspx
的reloadGrid()
進行更新頁面動作。btnCancel_OnClick()
取消時,直接關閉視窗。
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace PartyRegister.Admin.Member
{
public partial class Edit : System.Web.UI.Page
{
/// <summary>
/// 資料ID
/// </summary>
private string id;
/// <summary>
/// 連線字串
/// </summary>
private readonly string connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
protected void Page_Load(object sender, EventArgs e)
{
//Get the id from the query string
id = Request.QueryString["id"];
if (string.IsNullOrEmpty(id))
{
//alert message and close the window
Response.Write("<script>alert('查無相關資料');window.close();</script>");
Response.End();
}
if (!IsPostBack)
{
BindData();
}
}
/// <summary>
/// 讀取表單資料綁定至物件
/// </summary>
private void BindData()
{
string sql = @"SELECT Top 1 * FROM [Member] WHERE ID = @id";
var dt = new DataTable();
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
//read data
using (var comm = new SqlCommand(sql,conn))
using (var reader = new SqlDataAdapter(comm))
{
reader.SelectCommand.Parameters.AddWithValue("@id", id);
reader.Fill(dt);
//Bind data to the form
if (dt.Rows.Count > 0)
{
tbName.Text = dt.Rows[0]["Name"].ToString();
tbBirthday.Text = dt.Rows[0]["Birthday"].ToString();
tbEmail.Text = dt.Rows[0]["Email"].ToString();
tbPhone.Text = dt.Rows[0]["Phone"].ToString();
tbROCID.Text = dt.Rows[0]["ROCID"].ToString();
rbEventId.SelectedValue = dt.Rows[0]["EventId"].ToString();
rbGender.SelectedValue = dt.Rows[0]["Gender"].ToString();
rbFood.SelectedValue = dt.Rows[0]["Food"].ToString();
}
else
{
//alert message and close the window
Response.Write("<script>alert('查無相關資料');window.close();</script>");
Response.End();
}
}
}
}
protected void btnSubmit_OnClick(object sender, EventArgs e)
{
//update data
string sql = @"
UPDATE [Member]
SET
[Name] = @Name
,[Gender] = @Gender
,[Birthday] = @Birthday
,[ROCID] = @ROCID
,[Email] = @Email
,[Phone] = @Phone
,[Food] = @Food
,[EventID] = @EventID
WHERE ID=@id";
try
{
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
using (var comm = new SqlCommand(sql, conn))
{
comm.Parameters.AddWithValue("@Name", tbName.Text);
comm.Parameters.AddWithValue("@Gender", rbGender.SelectedValue);
comm.Parameters.AddWithValue("@Birthday", tbBirthday.Text);
comm.Parameters.AddWithValue("@ROCID", tbROCID.Text);
comm.Parameters.AddWithValue("@Email", tbEmail.Text);
comm.Parameters.AddWithValue("@Phone", tbPhone.Text);
comm.Parameters.AddWithValue("@Food", rbFood.SelectedValue);
comm.Parameters.AddWithValue("@EventID", rbEventId.SelectedValue);
comm.Parameters.AddWithValue("@id", id);
comm.ExecuteNonQuery();
}
//alert message 更新成功 並且呼叫父頁面的js reloadGrid()
Response.Write("<script>alert('更新成功'); window.opener.reloadGrid(); window.close();</script>");
Response.End();
}
}
catch (Exception exception)
{
//alert message 更新失敗
Response.Write("<script>alert('更新失敗');</script>");
Response.End();
Console.WriteLine(exception);
throw;
}
}
protected void btnCancel_OnClick(object sender, EventArgs e)
{
//close the window
Response.Write("<script>window.close();</script>");
Response.End();
}
}
}
Manage.aspx跟Edite.aspx互動
這邊流程就比較複雜,坑也不少。
在這邊描述需求步驟
- 使用者按下
Manage.aspx
的編輯,系統會開新視窗Edit.aspx
- 使用者在
Edit.aspx
修改好資料後 按下更新,Edit.aspx
這個視窗會- 存檔
- 關閉+呼叫
Manage.aspx
更新列
完整的Manager.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Admin/Admin.Master" AutoEventWireup="true" CodeBehind="Manage.aspx.cs" Inherits="PartyRegister.Admin.Member.Manage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<script>
var btnRebindId = '<%= btnRebind.UniqueID %>';
function reloadGrid() {
__doPostBack(btnRebindId, '');
}
function OpenDialog(url, width, height, showMenu, canResize, showScrollbars) {
var childWindow = window.open(url, "", "width=" + width + ",height=" + height + ",menubar=" + (showMenu ? "1" : "0") + ",scrollbars=" + (showScrollbars ? "1" : "0") + ",resizable=" + (canResize ? "1" : "0"));
if (childWindow) {
childWindow.resizeTo(width, height);
}
}
</script>
<h1>學員管理</h1>
<!-- 每頁筆數下拉選單 -->
每頁 <asp:DropDownList ID="ddlPageSize" runat="server" AutoPostBack="true" OnSelectedIndexChanged="ddlPageSize_SelectedIndexChanged">
<asp:ListItem Text="10" Value="10" Selected="True" />
<asp:ListItem Text="30" Value="30" />
<asp:ListItem Text="50" Value="50" />
<asp:ListItem Text="100" Value="100" />
<asp:ListItem Text="200" Value="200" />
</asp:DropDownList> 筆,查詢結果共<asp:Label ID="lbTotalCount" runat="server"></asp:Label>筆資料
<asp:Button ID="btnRebind" runat="server" OnClick="btnRebind_OnClick" CssClass="d-none" />
<asp:UpdatePanel ID="upGrid" runat="server">
<ContentTemplate>
<asp:GridView runat="server" ID="gvList" CssClass="table table-striped" AutoGenerateColumns="false" AllowCustomPaging="true"
AllowPaging="true" OnPageIndexChanging="gvList_PageIndexChanging" OnRowCommand="gvList_RowCommand">
<Columns>
<asp:TemplateField HeaderText="操作">
<ItemTemplate>
<asp:LinkButton
ID="btnEdit"
runat="server"
Text="編輯"
CssClass="text-primary"
OnClientClick='<%# string.Format("OpenDialog(\"Edit.aspx?id={0}\",850,625,false,false,true); return false;", Eval("ID")) %>'>
</asp:LinkButton>
|
<!-- 刪除按鈕,加入確認刪除提示 -->
<asp:LinkButton ID="btnDelete" runat="server" CommandName="DeleteData" Text="刪除" CommandArgument='<%# Eval("ID") %>' CssClass="text-danger"
OnClientClick="return confirm('是否確定刪除?');"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Name" HeaderText="姓名" SortExpression="Name"></asp:BoundField>
<asp:TemplateField HeaderText="性別" SortExpression="Gender">
<ItemTemplate>
<asp:Label ID="lblGender" runat="server"
Text='<%# Eval("Gender").ToString() == "1" ? "男" : "女" %>'
ForeColor='<%# Eval("Gender").ToString() == "1" ? System.Drawing.Color.Blue : System.Drawing.Color.Pink %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="EventID" HeaderText="場次" SortExpression="EventID"></asp:BoundField>
<asp:BoundField DataField="CreateTime" HeaderText="報名時間" SortExpression="CreateTime"
DataFormatString="{0:yyyy/MM/dd hh:mm}" />
</Columns>
</asp:GridView>
</ContentTemplate>
</asp:UpdatePanel>
</asp:Content>
完整的Manager.aspx.cs
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Web.UI.WebControls;
namespace PartyRegister.Admin.Member
{
public partial class Manage : System.Web.UI.Page
{
/// <summary>
/// 連線字串
/// </summary>
private readonly string connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
protected void Page_Load(object sender, EventArgs e)
{
//判斷頁面是第一次載入時才更新
if(!IsPostBack)
{
// 初始時依下拉選單預設值設定每頁筆數
gvList.PageSize = Convert.ToInt32(ddlPageSize.SelectedValue);
BindData();
}
}
/// <summary>
/// GridView 讀取資料表
/// </summary>
private void BindData()
{
//查詢結果總筆數
int totalCount = 0;
//分頁大小
int pageSize = gvList.PageSize;
//第幾頁
int pageIndex = gvList.PageIndex;
//計算要跳過幾筆
int offset = pageIndex * pageSize;
// 讀取資料庫指令
string sql = @"
SELECT [ID], [Name], [Gender], [EventID], [CreateTime]
FROM Member
ORDER BY [ID] ASC
OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY ;";
//string sql = @"SELECT * FROM Member";
// 取得資料
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
DataTable dt = new DataTable();
using (var cmd = new SqlCommand(sql,conn))
{
// 開始列
cmd.Parameters.AddWithValue("@Offset", offset);
cmd.Parameters.AddWithValue("@PageSize", pageSize);
// 使用 DataTable讀取資料
using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
{
adapter.Fill(dt);
}
}
//取得總共幾筆資料
string sqlCount = @"SELECT COUNT(1) FROM Member";
using (var cmd = new SqlCommand(sqlCount, conn))
{
totalCount = Convert.ToInt32(cmd.ExecuteScalar());
lbTotalCount.Text = totalCount.ToString();
}
// 設定 VirtualItemCount 使 GridView 分頁控制項能顯示正確總頁數
gvList.VirtualItemCount = totalCount;
gvList.DataSource = dt;
gvList.DataBind();
}
}
/// <summary>
/// GridView 分頁
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void gvList_PageIndexChanging(object sender, System.Web.UI.WebControls.GridViewPageEventArgs e)
{
//取得新的所在頁碼
var page = e.NewPageIndex;
//設定頁數
gvList.PageIndex = page;
//重新綁定資料
BindData();
}
/// <summary>
/// 下拉選單變更事件,更新 GridView 每頁筆數
/// </summary>
protected void ddlPageSize_SelectedIndexChanged(object sender, EventArgs e)
{
//取得每頁筆數設定
gvList.PageSize = Convert.ToInt32(ddlPageSize.SelectedValue);
// 重設頁碼,顯示第一頁
gvList.PageIndex = 0;
//重新綁定資料
BindData();
}
/// <summary>
/// GridView 按下編輯或刪除按鈕
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void gvList_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "DeleteData")
{
//刪除選定資料
string id = e.CommandArgument.ToString();
const string sql = "DELETE Member WHERE ID = @id ";
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
using (var cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("@id", id);
cmd.ExecuteNonQuery();
}
}
//刪除後重新載入列表
BindData();
}
}
protected void btnRebind_OnClick(object sender, EventArgs e)
{
BindData();
}
}
}
0 Comments