【问题标题】:How can I persist the data from a repeater after postback?回发后如何保留转发器中的数据?
【发布时间】:2010-07-01 18:17:39
【问题描述】:

我有一个中继器,可以显示各种股票的财务数据和价格。

在这个页面上,我还有一个“导出”按钮,需要将数据~在屏幕上~转换成CSV供用户使用。

问题是,在我对“库存”实体列表进行数据绑定后:

List<Stock> stocks = GetStocks()
rptStockList.DataSource = stocks;
rptStockList.DataBind();

回发时数据不会持久化。

此外,此页面上的数据通过 UpdatePanel 和 Timer 控件不断更新(每次都重新绑定数据)。中继器控件中显示的各种股票的价格每 30 秒变化一次。

现在,我有一个链接按钮,它在代码隐藏中有一个点击事件方法,应该为用户导出屏幕上的~数据~。我需要获取上次数据绑定到中继器的股票列表的当前值。我不能简单地从数据库中获取最新值,因为这些值会在上次刷新之间发生变化。

protected void lbtnExportStocks_Click(object sender, EventArgs e)
{
    // No longer have the stock data used in the repeater control
    ExportStocksToExcel();
}

我知道 ASP.NET 不会在回发时保留转发器的数据源,但我仍然需要能够重新构建这个 Stock 实体列表,以便我可以向它们发送 CSV,或者我需要持久化以某种方式。

我不想做任何在性能方面过于繁重的事情,因为在一周的某些日子里,这个应用程序可能会被大量使用。

这种情况的正确解决方案是什么?我应该遍历中继器的“项目”集合并重建 Stock 实体吗?

【问题讨论】:

  • 我认为您需要发布一些关于 ExportStocksToExcel() 究竟做了什么的信息,因为转发器不应丢失绑定到它的数据(假设您没有禁用控件或页面上的视图状态)因为视图状态。但是,如果这是您所期望的(或至少以任何合理的方式),您不能从中继器的数据源中向后读取数据。
  • @Chris Marisic,鉴于我上面写的内容,您个人如何从中继器取回数据以输出 CSV?
  • @Chris Marisic,到目前为止,所有 ExportStocksToExcel() 所做的只是设置正确的标题和内容类型,然后我打算用 CSV 数据写出响应。但是,我很难弄清楚如何取回这些数据。
  • @Chris 我认为丢失中继器中绑定的数据的情况不如希望中继器绑定来自的原始数据。我猜Stock 主要是一个股票代码和一个价格,所以你可能可以重建Stocks 但就像你说的那样,它会有点丑:-)

标签: asp.net ajax postback repeater


【解决方案1】:

你可以将stocks 存储在 Viewstate 或 Session 中吗?例如

List<Stock> stocks = GetStocks()
rptStockList.DataSource = stocks;
rptStockList.DataBind();

ViewState.Remove("stocks");
ViewState.Add("stocks", stocks);

private void ExportStocksToExcel
{
    List<Stock> persistedStocks;

    persistedStocks = (List<Stock>)Page.ViewState["stocks"];
    ...
}

会话状态实际上可能是存储Stocks 的更好选择,因为它不会在页面中传输到客户端(可能需要进行“创造性编辑”的所有可能性)——这在像这样的应用程序。 (是的,您可以加密 Viewstate,但要关注那些您可能不想要的开销的高峰时间。)

【讨论】:

    【解决方案2】:

    一种简单的方法是将值呈现为输入控件(与&lt;span&gt; 或裸&lt;td&gt; 元素相反)- 当用户发帖时,浏览器将输入值发送回服务器。

    例如:

    <ItemTemplate>
        Symbol: <input type="text" readonly="readonly" name="Symbol" value="<%# Container.DataItem("Symbol") %> />
        Quote: <input type="text" readonly="readonly" name="Quote" value="<%# Container.DataItem("Quote") %> />
    </ItemTemplate>
    

    客户端将每个名为“Symbol”的输入值发送到一个数组中(同样还有名为“Quote”的输入值),您可以像这样在代码隐藏中访问它们:

    protected void lbtnExportStocks_Click(object sender, EventArgs e) {
    
        // They come out as comma-delimited strings
        string[] symbols = Request.Form["Symbol"].Split(',');
        string[] quotes  = Request.Form["Quote"].Split(',');
    
        // ... continue exporting stocks to Excel
    }
    

    当然,归根结底,这种技术基本上是将客户端发送给您的任何内容写入 Excel 文件,因此您可能希望以某种方式保护或限制输入。这可能涉及对用户进行身份验证和/或限制您的方法将导出的数据量。如果这是您的环境中的一个严重问题,或者您无法给予太多关注,请考虑在用户会话中序列化原始数据。

    同样,如果您有意传输大量数据,出于性能原因,您应该考虑使用其他方法。您可以使用 session 代替,或者传输一个小密钥,您可以使用该密钥来重建用于构建转发器的数据(例如,如果转发器绑定到不改变其输入的查询结果,您可以只序列化调用之间的输入)。

    【讨论】:

      【解决方案3】:

      听起来好像在您的 Page_Load 方法中您正在对中继器进行某种绑定。出于您的目的,这很糟糕,正如您所看到的,它会在每次回发时取消保存您的数据。你能确保你的 Page_Load 东西是这样的吗? :

      Page_Load(...){
        if (! Page.IsPostBack){
          //first time page loads do this block
      
          //stuff
          //databinding stuff
        }
      }
      

      【讨论】:

      • 这就是我目前拥有的东西。这对我调用导出链接按钮时数据未持久化这一事实有何帮助?
      • @Darwin 数据可能会被持久化。例如。如果转发器包含用户可设置的文本框、列表框或复选框,则这些值 ARE 在回发时保持不变,除非您调用 DataBind。所以您的数据可能已经在ViewState 中了。您可以通过一个 runat="server" 按钮进行检查,该按钮只会导致 PostBack。如果您的数据保留,则在单击该按钮后它应该仍然存在。
      【解决方案4】:

      我要么接受 Phil 的回答并序列化整个数据集,要么创建某种标准对象,传递给 GetStocks() 以指定要获取的数据。然后将条件对象序列化并存储在 ViewState 中,这样当用户点击“导出”时,就可以拉取条件并检索相同的数据。

      即,

      [Serializable]
      public class StockCriteria
      {
          public DateTime DateFrom { get; set; }
          public DateTime DateTo { get; set; }
          public string[] Symbols { get; set; }
      }
      

      然后 GetStocks() 将 StockCriteria 作为参数并基于它创建查询。

      【讨论】:

      • 我认为您可能希望通过一个时间点,否则股票价格可能会在 DateFrom 和 DateTo 之间变化...
      猜你喜欢
      • 2012-04-12
      • 1970-01-01
      • 2017-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-25
      • 1970-01-01
      相关资源
      最近更新 更多