GridView中的控制項Postback後抓不到也無法保留使用者輸入的值(ViewState遺失)

  • 15236
  • 0
  • 2011-10-27

GridView中的控制項Postback後抓不到也無法保留使用者輸入的值(ViewState遺失)

Dotblogs 的標籤: ,

這個問題這些年來,被問過很多次了~在網路上搜尋,中英文也有很多人在問,不過很奇怪,大家都沒有一次到位的回答,所以昨天又被問到,乾脆寫一篇來記錄一下吧~

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>
Default.aspx.vb
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
 

--------
沒什麼特別的~
不過是一些筆記而已