回发后GridView事件意外引发



考虑以下Asp.net页面代码:

<head runat="server">
<title></title>
<script type="text/javascript">
        function showhide(master, detail) {
            var src = $(master).children()[0].src;
            if (src.endsWith("plus.png"))
                src = src.replace('plus.png', 'minus.png');
            else
                src = src.replace('minus.png', 'plus.png');
            $(master).children()[0].src = src;
            $(detail).slideToggle("normal");
        }
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
    <Scripts>
        <asp:ScriptReference Path="~/scripts/jquery-1.6.2.min.js" ScriptMode="Release" />
    </Scripts>
</asp:ScriptManager>
<div>
<asp:SqlDataSource ID="sqlDsCustomers" runat="server" ConnectionString="<%$ ConnectionStrings:Northwind %>"
    SelectCommand="SELECT [Customers].[CustomerID], [Customers].[CompanyName], COUNT([OrderID]) TotalOrders&#13;&#10;FROM [Customers] INNER JOIN [Orders] ON [Customers].[CustomerID]=[Orders].[CustomerID]&#13;&#10;Group By [Customers].[CustomerID], [Customers].[CompanyName]">
</asp:SqlDataSource>
    <asp:GridView Width="100%" AllowPaging="True" ID="gvCustomers" AutoGenerateColumns="False"
        DataSourceID="sqlDsCustomers" runat="server" ShowHeader="False" OnRowCreated="gvCustomers_RowCreated">
        <Columns>
            <asp:TemplateField>
                <ItemTemplate>
                    <div class="group" id='<%#String.Format("customer{0}",Container.DataItemIndex) %>'
                        onclick='showhide(<%#String.Format(""#customer{0}"",Container.DataItemIndex) %>,<%#String.Format(""#order{0}"",Container.DataItemIndex) %>)'>
                        <asp:Image ID="imgCollapsible" CssClass="first" ImageUrl="~/Assets/img/plus.png"
                            Style="margin-right: 5px;" runat="server" /><span class="header">
                                <%#Eval("CustomerID")%>
                                :
                                <%#Eval("CompanyName")%>
                                (<%#Eval("TotalOrders")%>Orders) </span>
                    </div>
                    <div id='<%#String.Format("order{0}",Container.DataItemIndex) %>' class="order">
                        <asp:GridView AutoGenerateColumns="false" CssClass="grid" ID="ddd" runat="server"
                            ShowHeader="true" EnableViewState="false">
                            <RowStyle CssClass="row" />
                            <AlternatingRowStyle CssClass="altrow" />
                            <Columns>
                                <asp:TemplateField ItemStyle-CssClass="rownum">
                                    <ItemTemplate>
                                        <%# Container.DataItemIndex + 1 %>
                                    </ItemTemplate>
                                </asp:TemplateField>
                                <asp:BoundField HeaderText="Order ID" DataField="OrderID" ItemStyle-Width="80px" />
                                <asp:BoundField HeaderText="Date Ordered" DataField="OrderDate" DataFormatString="{0:MM/dd/yyyy}"
                                    ItemStyle-Width="100px" />
                                <asp:BoundField HeaderText="Date Required" DataField="RequiredDate" DataFormatString="{0:MM/dd/yyyy}"
                                    ItemStyle-Width="110px" />
                                <asp:BoundField HeaderText="Freight" DataField="Freight" DataFormatString="{0:c}"
                                    ItemStyle-Width="50px" ItemStyle-HorizontalAlign="Right" />
                                <asp:BoundField HeaderText="Date Shipped" DataField="ShippedDate" DataFormatString="{0:MM/dd/yyyy}"
                                    ItemStyle-Width="100px" />
                            </Columns>
                        </asp:GridView>
                    </div>
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>
</div>
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />
</form>

和后面的代码:

protected void Page_Load(object sender, EventArgs e)
{
}
protected void gvCustomers_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        string custID = ((DataRowView)e.Row.DataItem)["CustomerID"].ToString();
        using (DataClassesDataContext dc=new DataClassesDataContext())
        {
            List<Order> ord = (from o in dc.Orders
                               where o.CustomerID == custID.Trim()
                               select o).ToList();

            GridView ctrl = e.Row.FindControl("ddd") as GridView;
            ctrl.DataSource = ord;
        }
    }
}
protected void Button1_Click(object sender, EventArgs e)
{
    Response.Redirect("Default.aspx");
}

问题是当我单击Button1重定向到另一个页面gvCustomers_RowCreated raise,我得到Null引用错误。为什么这个事件在回发后引发?


编辑1):

我删除了SqlDataSource并在后面的代码中绑定GridView,像这样:

public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        using (DataClassesDataContext dc=new DataClassesDataContext())
        {
            var query = dc.ExecuteQuery<clsRetern>("SELECT [Customers].[CustomerID], [Customers].[CompanyName], COUNT([OrderID]) TotalOrders FROM [Customers] INNER JOIN [Orders] ON [Customers].[CustomerID]=[Orders].[CustomerID] Group By [Customers].[CustomerID], [Customers].[CompanyName]").ToList();
            List<clsRetern> ret = new List<clsRetern>();
            foreach (var item in query)
            {
                clsRetern r = new clsRetern();
                r.CompanyName = item.CompanyName;
                r.CustomerID = item.CustomerID;
                r.TotalOrders = item.TotalOrders;
                ret.Add(r);
            }
            gvCustomers.DataSource = ret;
            gvCustomers.DataBind();        
        }
    }
}
protected void gvCustomers_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        string custID = ((clsRetern)e.Row.DataItem).CustomerID.Trim();
        using (DataClassesDataContext dc=new DataClassesDataContext())
        {
            List<Order> ord = (from o in dc.Orders
                               where o.CustomerID == custID.Trim()
                               select o).ToList();

            GridView ctrl = e.Row.FindControl("ddd") as GridView;
            ctrl.DataSource = ord;
        }
    }
}
protected void Button1_Click(object sender, EventArgs e)
{
    Response.Redirect("Default.aspx",true);
}
}
public class clsRetern
{
    public string CustomerID { get; set; }
    public string CompanyName { get; set; }
   public int TotalOrders { get; set; }
}

我尝试了Response.Redirect("Default.aspx");,但问题仍然存在。

如果你了解ASP。NET页面模型,那么这个问题不应该出现在你身上。每次请求到ASP。. NET页时,将创建一个新的页对象以及整个控件树,并在回发场景中使用视图状态管理状态。因此,在您的示例中,每当发生回发时,都会创建一个新的页面和网格视图。网格视图的数据将保存在新的视图状态中,网格将绑定到该数据。

无论是否显式调用DataBind,只要创建网格行,就会引发RowCreated事件。该事件的目的是为了让用户可以调整UI(网格视图单元格)——例如,如果需要,可以将一些控件推入网格视图单元格。无论post-back场景如何,都应该发生相同的情况,否则这些动态控件将不会被创建。通常,这些控件将使用view-state恢复其状态,并且您可以将网格视图UI(控件树)恢复为第一页循环时的状态。

这是因为即使你触发Response.Redirect, Page_Load事件仍然会被引发,如果你的GridView绑定代码不在!IsPostBack内,该代码将被击中。

试试这个。

protected void Page_Load(object sender, EventArgs e)
{
    try
    {
        if (!IsPostBack)
        {
            //bind gridview here
        }
    }
    catch (Exception exception)
    {
        //Elmah.ErrorSignal.FromCurrentContext().Raise(exception);
    }
}

精明?

将EnableViewState=False添加到page指令中,以防止每次回发时都运行"RowCreated"

最新更新