GridView中的控制項Postback後抓不到也無法保留使用者輸入的值(ViewState遺失)
這個問題這些年來,被問過很多次了~在網路上搜尋,中英文也有很多人在問,不過很奇怪,大家都沒有一次到位的回答,所以昨天又被問到,乾脆寫一篇來記錄一下吧~
111026 13:56 補充說明:此問題的案例是,原本開發人員是在 Page_Load 時,重新繫結 GridView。感謝 No.18 的提醒。
問題很簡單,就是GridView.DataBind()的時間點,比LoadViewState事件發生的時間晚,所以其實系統是有把使用者輸入的資料抓下來,也有試圖回覆GridView的ViewState資料,但是在那當下,GridView還沒有重新DataBind(),但是之後進入 Page_Load 事件時,重新執行了 GridView.DataBind(),所以重新產生的控制項就把先前 LoadViewState 的內容蓋掉了!所以當然無效嚕~
我建議的解決方法,就是把GridView的DataBind()放到Page_InitComplete,就可以了~
111026 18:28 補充:91 大推薦的正解,Not IsPostBack 時做 DataBind() 就好啦。(前提是沒有需求要每次 PostBack 都須更新查詢結果)。
111027 1127 No. 18 補充:指如果您的需求必須每次做DataBind(),那麼順序應該是在您要做的事件裡,而不應該把它放在Page Load做。(除非這隻程式 Postback 的處理必須在 Page_Load 中執行,例如:透過 html 控制項進行 Submit 的 Postback 行為)。
下面的範例,順便玩了一下DataBind時,Call Function處理,也是同時間被問的問題,就一併做了Sample。
下面範例說明:當Auth=Y時,CheckBox必須勾選,而且停用;至於兩個Button,只是測試抓值和清Label訊息用的。
Default.aspx
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="DataBinder中做條件判斷._Default" %> <!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:GridView ID="gvList" runat="server" AutoGenerateColumns="False" EnableViewState="true" > <Columns> <asp:BoundField DataField="Auth" HeaderText="Auth" /> <asp:TemplateField HeaderText="chk"> <ItemTemplate> <asp:CheckBox ID="cbxGet" runat="server" Checked='<%# Eval("Pick") %>' Enabled='<%# ReturnEnableProperty(Eval("Auth")) %>' /> </ItemTemplate> </asp:TemplateField> <asp:TemplateField HeaderText="temp"> <ItemTemplate> <asp:TextBox ID="txtAuth" runat="server" Text='<%# Eval("Auth") %>'></asp:TextBox> </ItemTemplate> </asp:TemplateField> </Columns> </asp:GridView> <br /> <asp:Button ID="btnSubmit" runat="server" Text="Submit" /> <asp:Button ID="btnReset" runat="server" Text="Reset" /> <br /> <asp:Label ID="lblShow" runat="server"></asp:Label> </div> </form> </body> </html>
Partial Public Class _Default Inherits System.Web.UI.Page Public dt As New DataTable Private Sub Page_InitComplete(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.InitComplete Dim c1 As New DataColumn Dim c2 As New DataColumn c1.ColumnName = "Auth" c2.ColumnName = "Pick" dt.Columns.Add(c1) dt.Columns.Add(c2) Dim dr As DataRow = dt.NewRow dr.Item(0) = "Y" dr.Item(1) = "True" dt.Rows.Add(dr) dr = dt.NewRow dr.Item(0) = "N" dr.Item(1) = "False" dt.Rows.Add(dr) gvList.DataSource = dt gvList.DataBind() End Sub Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load If IsPostBack = False Then CaluCheckedCount() End If End Sub Public Function ReturnEnableProperty(ByVal str As String) As Boolean If "Y".Equals(str) Then Return False Else Return True End If End Function Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSubmit.Click CaluCheckedCount() End Sub Public Sub CaluCheckedCount() Dim cbx As CheckBox Dim txt As TextBox Dim obj As Object = Request.Form("gvList") Dim i As Integer = 0 Dim gv As GridView If TypeOf (obj) Is GridView Then gv = CType(obj, GridView) Else gv = gvList End If For Each row As GridViewRow In gv.Rows obj = row.FindControl("cbxGet") If TypeOf (obj) Is CheckBox Then cbx = CType(obj, CheckBox) If cbx.Checked Then i += 1 lblShow.Text = i.ToString obj = row.FindControl("txtAuth") If TypeOf (obj) Is TextBox Then txt = CType(obj, TextBox) lblShow.Text += " = " + txt.Text End If End If End If Next End Sub Protected Sub btnReset_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnReset.Click lblShow.Text = "" End Sub End Class
--------
沒什麼特別的~
不過是一些筆記而已