[ASP.NET]Gridview+Formview實現無刷新更新
前陣子在公司內處理一個案子,客戶希望在一個畫面中能同時有Grid跟Detail fields,當初第一個直覺想到的就是透過Gridview搭配Formview來實現,但客戶接著又提了一個需求,說希望達到畫面無刷新的編輯與更新,也因此我寫了下面這個sample給專案團隊,請他們在做些修飾,以下我描述一下我進行的動作。
使用元件:UpdataPanel、Gridview、Formview、SqlDataSource
使用資料:Northwind中的Products資料表(由於Products資料表本身有一些contraints,所以我把資料倒到自己建立的Product資料表中)
《aspx》
- Gridview:
- 設定DataSource為SqlDataSource1,PageSize=5
- 多一個ItemTemplate,裡頭放兩個按鈕,一個是編輯,另一個是刪除,CommandName分別設定Edit跟Delete
CellPadding="4" DataKeyNames="ProductID" DataSourceID="SqlDataSource1" ForeColor="#333333"
GridLines="None" Height="253px" PageSize="5" Width="554px" OnRowCommand="GridView1_RowCommand" OnRowDataBound="GridView1_RowDataBound">
<RowStyle BackColor="#EFF3FB" />
<Columns>
<asp:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:Button ID="btnEdit" runat="server" CausesValidation="False" CommandName="Edit"
Text="編輯"></asp:Button>
<asp:Button ID="btnDelete" runat="server" CausesValidation="False" CommandName="Delete"
Text="刪除"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="ProductID" HeaderText="ProductID" ReadOnly="True" SortExpression="ProductID" />
<asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />
<asp:BoundField DataField="SupplierID" HeaderText="SupplierID" SortExpression="SupplierID" />
<asp:BoundField DataField="CategoryID" HeaderText="CategoryID" SortExpression="CategoryID" />
</Columns>
<FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<EditRowStyle BackColor="#2461BF" />
<AlternatingRowStyle BackColor="White" />
</asp:GridView>
- Formview
- 設定DataSource為SqlDataSource1,DefaultMode=Edit,裡頭繫結四個欄位
- 在下方放置兩個LinButton,用來做更新與取消,Command分別設為Update與Cancel
DataSourceID="SqlDataSource1" DefaultMode="Edit" ForeColor="#333333" Visible="False">
<FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
<RowStyle BackColor="#FFFBD6" ForeColor="#333333" />
<EditItemTemplate>
<table style="width: 400px">
<tr>
<td style="width: 100px; text-align: left">
ProductID</td>
<td style="width: 392px; text-align: left">
<asp:TextBox ID="txtProductID" runat="server" Text='<%# Bind("ProductID") %>'></asp:TextBox></td>
</tr>
<tr>
<td style="width: 100px; text-align: left">
ProductName</td>
<td style="width: 392px; text-align: left">
<asp:TextBox ID="txtProductName" runat="server" Text='<%# Bind("ProductName") %>'></asp:TextBox></td>
</tr>
<tr>
<td style="width: 100px; text-align: left">
SupplierID</td>
<td style="width: 392px; text-align: left">
<asp:TextBox ID="txtSupplierID" runat="server" Text='<%# Bind("SupplierID") %>'></asp:TextBox></td>
</tr>
<tr>
<td style="width: 100px; text-align: left">
CategoryID</td>
<td style="width: 392px; text-align: left">
<asp:TextBox ID="txtCategoryID" runat="server" Text='<%# Bind("CategoryID") %>'></asp:TextBox></td>
</tr>
</table>
<asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" CommandName="Update"
Text="更新"></asp:LinkButton>
<asp:LinkButton ID="CancelButton" runat="server" CausesValidation="False" CommandName="Cancel"
Text="取消"></asp:LinkButton>
</EditItemTemplate>
<PagerStyle BackColor="#FFCC66" ForeColor="#333333" HorizontalAlign="Center" />
<HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
</asp:FormView>
- SqlDataSource
- 分別設定好SelectCommand、DeleteCommand、UpdateCommand
SelectCommand="SELECT * FROM [product]"
DeleteCommand="DELETE FROM [product] WHERE [ProductID] = @ProductID"
UpdateCommand="UPDATE [product] SET [ProductName] = @ProductName, [SupplierID] = @SupplierID, [CategoryID] = @CategoryID WHERE [ProductID] = @ProductID"
OldValuesParameterFormatString="{0}">
<DeleteParameters>
<asp:Parameter Name="ProductID" Type="Int32" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="ProductName" Type="String" />
<asp:Parameter Name="SupplierID" Type="String" />
<asp:Parameter Name="CategoryID" Type="String" />
</UpdateParameters>
</asp:SqlDataSource>
《cs》
- RowDataBound
- 為了在按下「編輯」鈕時可以將筆資料的明細帶到Formview中,所以在 RowDataBound 事件中,去設定「編輯」鈕的 CommandArgument 屬性值為 RowIndex。
{
Button tButton = new Button();
//如果是DataRow
if (e.Row.RowType == DataControlRowType.DataRow)
{
//設定編輯鈕的 CommandArgument
tButton = (Button)e.Row.Cells[0].FindControl("btnEdit");
//按下Edit按鈕時,CommandArgument為該筆資料的index
tButton.CommandArgument = e.Row.RowIndex.ToString();
}
}
- RowCommand
- 接著在RowCommand的事件中加入按下「編輯」鈕時,要將Gridview點選的資料帶入Formview中,並將Formview的模式切換為編輯模式
{
int tEditIndex=0;
switch(e.CommandName)
{
case "Edit":
//根據有沒有分頁來取得目前實際的index,避免換頁後取錯資料
tEditIndex = getNowIndex(Convert.ToInt32(e.CommandArgument));
FormView1.PageIndex = tEditIndex;
FormView1.ChangeMode(FormViewMode.Edit); //將FormView切換到編輯模式
FormView1.Visible = true;
break;
default:
break;
}
}
/// <summary>
/// 傳入目前頁面上的index,回傳實際的index
/// </summary>
/// <param name="pRowIndex">目前頁面上的index</param>
/// <returns>根據分頁來計算實際的index</returns>
private int getNowIndex(int pRowIndex)
{
int tEditIndex=0;
if (GridView1.AllowPaging)
{
//GridView有分頁時,index=頁次*分頁大小+頁面的index
tEditIndex = (GridView1.PageIndex) * GridView1.PageSize + pRowIndex;
}
else
{
//GridView無分頁時,直接使用pRowIndex
tEditIndex = pRowIndex;
}
return tEditIndex;
}
進行到這邊,只寫幾行code,我們已經可以順利的編輯Product這個Table的資料了,如下圖:
但做到這邊可以交差了嗎?還沒,因為客戶要求要無刷新的操作,期望的結果是:
- 在Gridview中按下編輯時,將該筆資料帶到Formview中,不能全頁刷新,只刷新Formview(條件一)
- 在Gridview中按下刪除時,將該筆資料從Gridview中刪除,不能全頁刷新,刷新Gridview與Formview(條件二)
- 在Formview中按下更新,該筆資料會被更新回Gridview中,不能全頁刷新,只刷新Gridview(條件三)
所以我又做了幾個小動作,UpdatePanel這東西這麼好用,怎麼可以不用呢? 我們依以下步驟進行設定:
- 在畫面上拉一個ScriptManager
- 在畫面上拉一個UpdatePanel,名稱為UpdatePanel2,將Gridview放到裡頭
- 設定UpdatePanel的屬性:需特別留意
- ChildAsTriggers要設定為False,否則當您按下編輯或者刪除鈕時,Gridview都會被更新
- UpdateMode設定為Conditional,否則只要有trigger被觸發時,則這個UpdatePanel不管怎樣都會刷新
- 設定UpdatePanel的Triggers,我總共加了兩個Trigger
- 第一個是Gridview1的RowDeleted,為了滿足條件二
- 第二個是FormView1的ItemUpdate,為了滿足條件三
- 再拉一個UpdatePanel,名稱為UpdatePanel1,將Formview放在裡頭
- 一般屬性設定上與UpdatePanel2相同
- 而在Triggers的設定上略有不同,一樣有兩個Triggers:
- 第一個是Gridview1的RowEditing,為了滿足條件一
- 第二個是Gridview1的RowDeleted,為了滿足條件二
做完這些動作後,我們再操作一下,果然發現我們可以做到部分刷新而完成資料的更新,這也算是單單使用微軟提供的元件來達到客戶想要的效果了,不過這一段程式碼後來專案成員有再做一些操作性的改良,我也沒深究,這邊PO給大家參考,但如果要照抄的話,建議您再測試看看,以下為完整的程式碼:
《aspx》
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>未命名頁面</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<br />
<asp:UpdatePanel ID="UpdatePanel2" runat="server" ChildrenAsTriggers="False" UpdateMode="Conditional">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="GridView1" EventName="RowDeleted" />
<asp:AsyncPostBackTrigger ControlID="FormView1" EventName="ItemUpdated" />
</Triggers>
<ContentTemplate>
<asp:GridView ID="GridView1" runat="server" AllowPaging="True" AutoGenerateColumns="False"
CellPadding="4" DataKeyNames="ProductID" DataSourceID="SqlDataSource1" ForeColor="#333333"
GridLines="None" Height="253px" PageSize="5" Width="554px" OnRowCommand="GridView1_RowCommand" OnRowDataBound="GridView1_RowDataBound">
<RowStyle BackColor="#EFF3FB" />
<Columns>
<asp:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:Button ID="btnEdit" runat="server" CausesValidation="False" CommandName="Edit"
Text="編輯"></asp:Button>
<asp:Button ID="btnDelete" runat="server" CausesValidation="False" CommandName="Delete"
Text="刪除"></asp:Button>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="ProductID" HeaderText="ProductID" ReadOnly="True" SortExpression="ProductID" />
<asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />
<asp:BoundField DataField="SupplierID" HeaderText="SupplierID" SortExpression="SupplierID" />
<asp:BoundField DataField="CategoryID" HeaderText="CategoryID" SortExpression="CategoryID" />
</Columns>
<FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<EditRowStyle BackColor="#2461BF" />
<AlternatingRowStyle BackColor="White" />
</asp:GridView>
</ContentTemplate>
</asp:UpdatePanel>
<br />
</div>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="False">
<ContentTemplate>
<asp:FormView ID="FormView1" runat="server" CellPadding="4" DataKeyNames="ProductID"
DataSourceID="SqlDataSource1" DefaultMode="Edit" ForeColor="#333333" Visible="False">
<FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
<RowStyle BackColor="#FFFBD6" ForeColor="#333333" />
<EditItemTemplate>
<table style="width: 400px">
<tr>
<td style="width: 100px; text-align: left">
ProductID</td>
<td style="width: 392px; text-align: left">
<asp:TextBox ID="txtProductID" runat="server" Text='<%# Bind("ProductID") %>'></asp:TextBox></td>
</tr>
<tr>
<td style="width: 100px; text-align: left">
ProductName</td>
<td style="width: 392px; text-align: left">
<asp:TextBox ID="txtProductName" runat="server" Text='<%# Bind("ProductName") %>'></asp:TextBox></td>
</tr>
<tr>
<td style="width: 100px; text-align: left">
SupplierID</td>
<td style="width: 392px; text-align: left">
<asp:TextBox ID="txtSupplierID" runat="server" Text='<%# Bind("SupplierID") %>'></asp:TextBox></td>
</tr>
<tr>
<td style="width: 100px; text-align: left">
CategoryID</td>
<td style="width: 392px; text-align: left">
<asp:TextBox ID="txtCategoryID" runat="server" Text='<%# Bind("CategoryID") %>'></asp:TextBox></td>
</tr>
</table>
<asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" CommandName="Update"
Text="更新"></asp:LinkButton>
<asp:LinkButton ID="CancelButton" runat="server" CausesValidation="False" CommandName="Cancel"
Text="取消"></asp:LinkButton>
</EditItemTemplate>
<PagerStyle BackColor="#FFCC66" ForeColor="#333333" HorizontalAlign="Center" />
<HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
</asp:FormView>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="GridView1" EventName="RowEditing" />
<asp:AsyncPostBackTrigger ControlID="GridView1" EventName="RowDeleted" />
</Triggers>
</asp:UpdatePanel>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
SelectCommand="SELECT * FROM [product]"
DeleteCommand="DELETE FROM [product] WHERE [ProductID] = @ProductID"
UpdateCommand="UPDATE [product] SET [ProductName] = @ProductName, [SupplierID] = @SupplierID, [CategoryID] = @CategoryID WHERE [ProductID] = @ProductID"
OldValuesParameterFormatString="{0}">
<DeleteParameters>
<asp:Parameter Name="ProductID" Type="Int32" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="ProductName" Type="String" />
<asp:Parameter Name="SupplierID" Type="String" />
<asp:Parameter Name="CategoryID" Type="String" />
</UpdateParameters>
</asp:SqlDataSource>
</form>
</body>
</html>
《cs》
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class PartialForm : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
Button tButton = new Button();
//如果是DataRow
if (e.Row.RowType == DataControlRowType.DataRow)
{
//設定編輯鈕的 CommandArgument
tButton = (Button)e.Row.Cells[0].FindControl("btnEdit");
//按下Edit按鈕時,CommandArgument為該筆資料的index
tButton.CommandArgument = e.Row.RowIndex.ToString();
}
}
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
int tEditIndex=0;
switch(e.CommandName)
{
case "Edit":
//根據有沒有分頁來取得目前實際的index,避免換頁後取錯資料
tEditIndex = getNowIndex(Convert.ToInt32(e.CommandArgument));
FormView1.PageIndex = tEditIndex;
FormView1.ChangeMode(FormViewMode.Edit); //將FormView切換到編輯模式
FormView1.Visible = true;
break;
default:
break;
}
}
/// <summary>
/// 傳入目前頁面上的index,回傳實際的index
/// </summary>
/// <param name="pRowIndex">目前頁面上的index</param>
/// <returns>根據分頁來計算實際的index</returns>
private int getNowIndex(int pRowIndex)
{
int tEditIndex=0;
if (GridView1.AllowPaging)
{
//GridView有分頁時,index=頁次*分頁大小+頁面的index
tEditIndex = (GridView1.PageIndex) * GridView1.PageSize + pRowIndex;
}
else
{
//GridView無分頁時,直接使用pRowIndex
tEditIndex = pRowIndex;
}
return tEditIndex;
}
}
游舒帆 (gipi) 探索原力Co-founder,曾任TutorABC協理與鼎新電腦總監,並曾獲選兩屆微軟最有價值專家 ( MVP ),離開職場後創辦探索原力,致力於協助青少年培養面對未來的能力。認為教育與組織育才其實息息相關,都是在為未來儲備能量,2018年起成立為期一年的專題課程《職涯躍升的關鍵24堂課》,為培養台灣未來的領袖而努力。 |