【问题标题】:On Postback, the DataTable data source for a Repeater is empty?在 Postback 上,Repeater 的 DataTable 数据源为空?
【发布时间】:2012-01-31 00:52:03
【问题描述】:

背景

我有一个用户控件(一个 .ascx 文件),它被动态插入到页面上的 asp:PlaceHolder 控件中。该用户控件包含一个asp:Repeater,我将其绑定到一个DataTable。

理论上,在用户控件第一次加载时,DataTable 会被初始化并添加 3 个空行。用户控件上的一个按钮将额外的空行添加到中继器,一次一个。

问题

问题是页面上的任何 PostBack 事件(即本例中的按钮被单击)后,Repeater 的 DataTable 为空。

用户控制 (.ascx) (简体)

<asp:TextBox ID="controlOutsideRepeater" runat="server" />
<asp:Repeater ID="myRepeater" runat="server">
  <ItemTemplate>
    <p><asp:Textbox ID="firstControlInRepeater" runat="server" text='<%# DataBinder.Eval(Container.DataItem, "A") %>' /></p>
    <p><asp:Textbox ID="secondControlInRepeater" runat="server" text='<%# DataBinder.Eval(Container.DataItem, "B") %>' /></p>
  </ItemTemplate>
</asp:Repeater>
<asp:LinkButton ID="addItemButton" runat="server" Text="Add Item" onclick="addNewItem" />

代码隐藏 (.ascx.cs) (也简化了)

public DataTable items {
  get {
    object i = ViewState["items"];
    if (i == null) {
      DataTable t = new DataTable();
      t.Columns.Add("A");
      t.Columns.Add("B");
      // add 3 blank items/rows:
      t.Rows.Add(t.NewRow());
      t.Rows.Add(t.NewRow());
      t.Rows.Add(t.NewRow());
      ViewState["items"] = t;
      return t;
    } else {
      return (DataTable)i;
    }
  set { ViewState["items"] = value; }
}

protected void Page_Init(object sender, EventArgs e) {
  myRepeater.DataSource = this.items;
  myRepeater.DataBind();
}

public void addNewItem(object sender, EventArgs e) {
  DataRow r = this.items.NewRow();
  this.items.Rows.Add(r);
  myRepeater.DataBind();
}

行为

第一次加载 UserControl 时,Repeater 包含 3 个空项:好!但是,在中继器内外的文本框中输入一些文本并单击“添加项目”链接按钮后,页面会进行刷新/回发并显示 4 个空项目,但是中继器外部的文本框保留它的文本。再次单击“添加项目”链接按钮也会执行回发,仍然显示 4 个空项目,但中继器外部的文本框再次保留它的文本。

我的疯狂猜测

我尝试将 Repeater 数据绑定包装在 (!Page.IsPostBack) 中,但这阻止了 Repeater 被绑定,因为 UserControl 仅在 PostBack 之后以编程方式添加到页面( Page 在单击时添加 UserControl,然后 Page 检查每个 PostBack 以查看是否应该存在用户控件,并在需要时将其重新添加到 Page)。所以我猜测页面在每个 PostBack 上重新创建用户控件存在问题,但无法解释为什么中继器之外的 TextBox 会保留它的值,以及为什么 ViewState 似乎不记得我的项目(在每个回发 ViewState["items"] 为 null 并在 getter 中重新构建)。

帮助!

【问题讨论】:

    标签: c# asp.net user-controls


    【解决方案1】:

    问题是,当您真的只想对第一个请求进行数据绑定时,您正在对每个请求进行数据绑定。由于您没有在第一个页面加载时进行数据绑定,因此您必须检查您是否以 !Page.IsPostBack 以外的方式进行数据绑定。您可以向用户控件添加一个属性来处理此问题,然后检查每个页面加载/页面初始化。

    更新:来自 cmets 的更多详细信息

    我现在看到了您的 AddItem()。尽管我不完全确定原因,但我在以这种方式使用视图状态时遇到了问题。我不得不像以下那样做:

    public void addNewItem(object sender, EventArgs e) {
      DataTable theItems = this.items;
      DataRow r = theItems.NewRow()
      theItems.Rows.Add(r);
      this.items = theItems
      myRepeater.DataBind(); //I'm not sure if this belongs here because of the reasons said before
    }
    

    【讨论】:

    • 感谢您的回复。我通过向我的页面添加一个空标签来尝试此操作,并在 Page_Load 检查标签的文本是否为空。如果为空,我为标签设置一个文本值并进行数据绑定(我注释掉了 Page_Init 中的数据绑定),如果标签有一个文本值,我跳过数据绑定。结果是转发器第一次被正确绑定(带有 3 个空项),但在随后的回发中根本没有绑定。这里的一些搜索表明Repeaters需要在每个请求上绑定......
    • 我不知道中继器的这种行为。 MSDN 上的这篇文章有一个示例,所有绑定都发生在 if !IsPostBack 块中。 msdn.microsoft.com/en-us/library/s1th73f0.aspx 我唯一的另一个猜测是视图状态没有被更新或正确读取。如果你有 3 个空白行,听起来它的绑定很好。问题是每次的视图状态都是空的。你什么时候写回 ViewState(除了你的 set 方法)?
    • 只是在 getter 和 setter 中,间接在 addItem() 事件处理程序中(因为它调用 setter)
    • 用更多信息更新了我的答案 - 希望我们能深入了解这一点。
    • 天哪,我爱你。不是 100% 确定您的更新是完整的解决方案,但一目了然(我现在已经在办公室工作了 12 多个小时),在删除了该 Repeater.DataBind() 之后,它看起来一切正常。 (更新:viewState 中的数据表仍然存在其他问题。我明天会解决这个问题并将其标记为答案,如果确实如此)
    猜你喜欢
    • 1970-01-01
    • 2019-12-03
    • 1970-01-01
    • 1970-01-01
    • 2013-06-21
    • 1970-01-01
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多