PostBack 期间 GridView.DataSource 为空

Posted

技术标签:

【中文标题】PostBack 期间 GridView.DataSource 为空【英文标题】:GridView.DataSource is null during PostBack 【发布时间】:2015-01-11 22:48:26 【问题描述】:

我想从我的应用程序中的每个 Gridview 实现打印/下载 csv。那些通过数据源或直接通过

gvSample.DataSource = Data;
gvSample.DataBind();

现在我的第一个方法是在页脚模板中设置一个下载按钮并在那里处理下载

<asp:GridView ID="gvSample" runat="server">
 <PagerTemplate>
  <asp:ImageButton  ImageUrl="~/download.gif"  OnClick="dl_Click" runat="server" ID="dl"/>
 </PagerTemplate>
</asp:GridView>

protected void dl_Click(object sender, ImageClickEventArgs e)

    GridView gv = (GridView)this.Parent.Parent.Parent.Parent;
    string csv = ToCSV(gv.DataSource); //gv.DataSource is null, DatasourceID aswell
    Response.ContentType = "application/csv";
    Response.AddHeader("content-disposition", "attachment; filename=file.csv");
    Response.Write(csv);
    Response.End();           

但我无法访问数据。

【问题讨论】:

粘贴整个 gridview .aspx 代码 在使用 jQuery TableTools 或 RadGrid 的自定义导出方法之前,我只能处理这个问题。 DataSource 本质上是只写的,在后续调用中它将为空,因为数据现在已绑定。我想你可以通过将数据放在 Session 或 ViewState 中来处理这个问题 - 但在这两种情况下,我强烈建议你不要这样做。 不要使用字符串 csv = ToCSV(gv.DataSource),尝试使用字符串 csv = ToCSV(Data) 我能指出 CSV 不是一种很好的数据传输格式吗?相反,您应该使用 Open Office XML 电子表格/Excel 文件(如果打算供人类使用)或 XML/JSON(如果打算供计算机使用)。此外,GridView 是一个 UI 控件。它不应作为应用程序中的数据源。 【参考方案1】:

GridView 中的DataSource 不会在Postback 中以任何持久方式存储,因此您必须将其保存在某处(Viewstate 或Session),否则您必须从数据存储区再次请求它(是你的数据库)。

三种方法的快速解释:

VievState:保存在页面的隐藏字段中,因此不建议用于大型数据集,因为您的页面可能会变得很多 MB。它的优点是它保存在页面中所以它不会过期

ViewState["Data"] = GetData();
gvSample.DataSource = ViewState["Data"];
gvSample.DataBind();

...

protected void dl_Click(object sender, ImageClickEventArgs e)

    string csv = ToCSV(ViewState["Data"]);
    ...   

会话:保存在服务内存中,因此您“相当”没有大小问题,但会话不会永远持续(通常为 30 分钟),如果用户显示该页面并在之后点击下载一个小时后的会话将是空的

Session["Data"] = GetData();
gvSample.DataSource = Session["Data"];
gvSample.DataBind();

...

protected void dl_Click(object sender, ImageClickEventArgs e)

    string csv = ToCSV(Session["Data"]);
    ...   

来自数据存储的请求您从数据库请求数据,这样就完成了另一次往返,数据可能与用户看到的不同

gvSample.DataSource = GetData();
gvSample.DataBind();

...

protected void dl_Click(object sender, ImageClickEventArgs e)

    string csv = ToCSV(GetData());
    ...   

只是一个建议:

您可以直接使用gvSample 访问更简单的网格,这样,如果您更改您的html,它不会被破坏...:

protected void dl_Click(object sender, ImageClickEventArgs e)

    //GridView gv = (GridView)this.Parent.Parent.Parent.Parent;
    //string csv = ToCSV(gv.DataSource); //gv.DataSource is null, DatasourceID aswell
    string csv = ToCSV(gvSample.DataSource);
    ...   

【讨论】:

@fubo 是的,我忘记了 gridview 中的数据源不会自动存储在 viestate 中(就像在其他 asp.net 控件中一样)。您必须将其保存在某处或从您的数据存储区再次请求。检查我更新的答案【参考方案2】:

您可以将数据保存在ViewState 中(不推荐用于大型数据集!!!),大致

gvSample.DataSource = Data;
ViewState["Data"] = Data;
gvSample.DataBind();

protected void dl_Click(object sender, ImageClickEventArgs e)

    var ds = (ProperDataType)ViewState["Data"]; // TODO: check for nulls
    string csv = ToCSV(ds); //gv.DataSource is null, DatasourceID aswell
    Response.ContentType = "application/csv";
    Response.AddHeader("content-disposition", "attachment; filename=file.csv");
    Response.Write(csv);
    Response.End();           

此外,您可以基于 gridview 重建数据,例如

var ds = new ProperDataSource();
foreach(GridViewRow row in gvSample.Rows)

    dRow data = new dRow();
    foreach(TableCell cell in row.Cells)
    
        ds.Add("column1", cell.Text);
    
    ds.Add(dRow);

string csv = ToCSV(ds); //gv.DataSource is null, DatasourceID aswell
        Response.ContentType = "application/csv";
        Response.AddHeader("content-disposition", "attachment; filename=file.csv");
        Response.Write(csv);
        Response.End();  

当然,您必须使这个 sn-p 适合您的特定数据结构......但这是一般的想法。

GridViews 不会保存它的原始数据源,您必须将其保存在其他地方或按需重建它

【讨论】:

【参考方案3】:

你不能像你编码的那样访问它 gv.DataSource

尝试使用SessionViewStates 并保存DataTable

gvSample.DataSource = Data;
gvSample.DataBind();
Session["MyTable"]=Data;

Session 转换为DataTable 并传递给方法

protected void dl_Click(object sender, ImageClickEventArgs e)

    if(Session["MyTable"]==null)


    string csv = ToCSV(DataTable(Session["MyTable"]) );  
    Response.ContentType = "application/csv";
    Response.AddHeader("content-disposition", "attachment; filename=file.csv");
    Response.Write(csv);
    Response.End();    

       

【讨论】:

以上是关于PostBack 期间 GridView.DataSource 为空的主要内容,如果未能解决你的问题,请参考以下文章

WebPart 上的用户控件、PostBack / ViewState 问题

为啥我的 PostBack 在我的 jQuery 点击事件之前发生?

WindowsIdentity.Impersonate 和 PostBack 问题

PostBack IsPostBack

text mns_postback

使用 PostBack 数据浏览页面 javascript Python Scrapy