c# - 当页面回发时,ASP.NET ListView-embedded Web-Control 在 ItemDataBound 事件处理程序上丢失状态和传递值

标签 c# asp.net postback web-controls

这个问题是关于网络控件的一种非常奇怪的行为。请考虑以下内容。

设想

我有一个用于显示一些数据的 web 控件。 MyWebControl.ascx文件如下:

<%@ Control ViewStateMode="Enabled" 
            Language="C#" 
            AutoEventWireup="true" 
            CodeFile="MyWebControl.ascx.cs" 
            Inherits="MyWebControl" %>

<div>
   <asp:Label ID="MyLabel1" runat="server"></asp:Label>
   <asp:Label ID="MyLabel2" runat="server"></asp:Label>
</div>

和后面的代码 MyWebControl.ascx.cs是:
public partial class MyWebControl : 
      System.Web.UI.UserControl {
   protected string str1;
   protected string str2;

   public string Str1 {
      get { return this.str1; }
      set { this.str1 = value; }
   }
   public string Str2 {
      get { return this.str2; }
      set { this.str2 = value; }
   }

   protected void Page_Load(object sender, EventArgs e) {
      this.MyLabel1.Text = this.str1;
      this.MyLabel2.Text = this.str2;
   }
}

好吧,我在 ListView 中使用了这个控件我在一个普通的网络表单中。此 Web 表单称为 Default.aspx接下来,我展示了它的一段代码,只有 ListView居住在:
<%@ Page Title="My page" Language="C#" AutoEventWireup="true"
         CodeFile="Default.aspx.cs" Inherits="_Default" %>

<%@ Register TagPrefix="my" TagName="MyWC" Src="~/MyWebControl.ascx" %>
...
...
<div>
   <asp:ListView ID="MyLV_ListView" runat="server" 
                 EnableViewState="true" 
                 OnPreRender="MyLV_ListView_PreRender" 
                 OnItemDataBound="MyLV_ListView_ItemDataBound">
      <ItemTemplate>
         <my:MyWC ID="WC_MyWC" runat="server" />
      </ItemTemplate>
   </asp:ListView>
</div>

此 Web 表单代码隐藏 Default.aspx.cs是:
public partial class _Default : System.Web.UI.Page {
   protected void Page_Load(object sender, EventArgs e) {
      if (!this.IsPostBack) {
         DAO d = new DAO(...); /* This object will contain some data */
                               /* Data are somehow paged, changing index, we have other data */
                               /* Please do not worry about paging, it works, problem is another */
         d.PageIndex = 0;
         this.ViewState["DAO"] = d; /* DAO is serializable */
         this.ViewState["PageIndex"] = 0;
         Data[] data = d.GetData(); /* Returns an array of objects representing my data */
                                    /* Custom way of storing data in objects */
                                    /* GetData use the PageIndex to get only a range of results */
         this.MyLV_ListView.DataSource = data;
         this.MyLV_ListView.DataBind();
      }
   }
   protected void MyLV_ListView_ItemDataBound(object sender, ListViewItemEventArgs e) {
      if (e.Item.ItemType == ListViewItemType.DataItem) {
         ((MyWebControl)e.Item.FindControl("WC_MyWC")).Str1 = 
            ((Data)e.Item.DataItem).DataField1;
         ((MyWebControl)e.Item.FindControl("WC_MyWC")).Str2 = 
            ((Data)e.Item.DataItem).DataField2;
      }
   }
   protected void MyLV_ListView_PreRender(object sender, EventArgs e) {
      if (this.IsPostBack)
         this.MyLV_ListView.DataBind();
   }
   // A TreeView will cause the page to reload, 
   // this is the handler called when a tree node is 
   // selected, the node is used to change the page 
   // for showing data in my listview.
   protected void MyLVPaging_TreeView_SelectedNodeChanged(object sender, EventArgs e) {
      this.ViewState["PageIndex"] = int.Parse(this.MyLVPaging_TreeView.SelectedNode.Value);
      ((DAO)this.ViewState["DAO"]).PageIndex = (int)this.ViewState["PageIndex"];
      // After setting the new index, GetData will return another set of results
      this.MyLV_ListView.DataSource = ((DAO)this.ViewState["DAO"]).GetData();
   }
}

问题

我的问题是什么???

好吧,当页面第一次加载时,我可以在 ListView 中看到一些数据,所以一切正常。

当我选择另一个页面时,我会导致页面重新加载并回发...我的 ListView将显示正确数量的条目,但其中没有数据。 Web 控件的放置次数与检索到的数据记录的数量一样多,但 Web 控件中没有数据。

调试结果

我进行了一些调试 session ,这就是发生的事情,请跟我来,我想这是非常重要的理解。

第一次加载页面

1) Load页面方法被执行。

2) ListViewItemDataBound事件处理程序被执行。好吧,假设我在 Data[] 中有三个元素DataSource 中的数组,处理程序被调用了 3 次。在继续调试方法时检查值,我可以看到 ((Data)e.Item.DataItem).DataField1((Data)e.Item.DataItem).DataField2是从 ListView 中的绑定(bind)数据源检索到的正确值.
方法执行后,调试器光标移动到MyWebControl.ascx.cs到控件的Page_Load方法。我可以看到,检查变量,发生这种情况:
protected void Page_Load(object sender, EventArgs e) {
   this.MyLabel1.Text = this.str1; // <-- this.str1 has the correct value loaded in the list view itemdatabound event handler.
   this.MyLabel2.Text = this.str2; // <-- this.str2 has the correct value loaded in the list view itemdatabound event handler.
}

3) ListView PreRender方法被调用。

4) 页面显示,一切正常!

在 TreeView 中选择一个节点后返回的页面

1) Load page 方法已执行,但它什么也不做。

2) MyLVPaging_TreeView_SelectedNodeChanged被执行。在这里我可以看到一切都有正确的值(value):

protected void MyLVPaging_TreeView_SelectedNodeChanged(对象发送者,EventArgs e){
this.ViewState["PageIndex"] =
int.Parse(this.MyLVPaging_TreeView.SelectedNode.Value);//<-- 新页面
((DAO)this.ViewState["DAO"]).PageIndex =
(int)this.ViewState["PageIndex"];//<-- 索引已保存
//设置新索引后,GetData 会返回另一组结果
this.MyLV_ListView.DataSource =
((DAO)this.ViewState["DAO"]).GetData();//<-- 数据源已更改
}

3) ListViewItemDataBound事件处理程序被执行。嗯,到这里,调试我可以看到和以前一样,我的意思是,我可以看到新的值,新的Data已绑定(bind)ListView ,实际上我可以检查分配给模板项的新值。
显然,和之前一样,方法执行后,调试器光标移动到MyWebControl.ascx.cs到控件的Page_Load方法。
这是邪恶的:我可以看到以下内容:
protected void Page_Load(object sender, EventArgs e) {
   // Note: inspecting this.IsPostBack I get true!
   this.MyLabel1.Text = this.str1; // <-- this.str1 is null and also this.MyLabel1.Text is null.
   this.MyLabel2.Text = this.str2; // <-- this.str2 is null and also this.MyLabel1.Text is null. view itemdatabound event handler.
}

Well!!! IT LOSES STATE AND ALSO VALUES PASSED BY THE LIST VIEW HANDLER!!!!!!!!!



我的问题

这到底是怎么回事???

笔记

1) 请不要过多关注我如何管理 Load 上的数据绑定(bind)和 PreRender事件...我感觉这不是错误!我想这与页面生命周期有关。但是,如果您认为这是重要的细节,请告诉我。

2) DAO及其功能GetData()是一种让您尽可能快地理解更清晰的场景的方法,但与我在这里展示的完全相同的结构。

谢谢您的帮助。

最佳答案

从我的评论:

Why don't you move the this.MyLV_ListView.DataBind() from PreRender to SelectedNodeChanged? And why do you need the fields str1 and str2 in your UserControl? The property Str1 should get/set this.MyLabel1.Text and the property Str2should get/set this.MyLabel2.Text, because the lables' Text are already stored in ViewState.



安德里:

... so these kind of settings are not to be made in the Load?



我:

you don't need to wait for any event to happen to set the label's text. The properties should directly lead to the corresponding Labels, hence your fields str1 and str2 are redundant. They will be disposed at the end of the Page-Lifecycle as opposed to the Text property of the Labels which are stored in ViewState automatically across postbacks.

关于c# - 当页面回发时,ASP.NET ListView-embedded Web-Control 在 ItemDataBound 事件处理程序上丢失状态和传递值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6461255/

相关文章:

c# - 读取中间件.Net Core中的Controller和Action名称

c# - Protobuf-net序列化byte[]数据,每个字节前加 '00'

asp.net - 具有自动完成 ASP.NET 和数据库的搜索字段

c# - linq 查询从表中选择评论最多的前 10 个条目

php - ASP.net 调用 javascript,然后将值返回给后面的代码

javascript - 在 ASP.NET 代码中通过 javascript 重置 Jquery 验证后停止回发

c# - 回发后如何保持 DropDownList1 的选定值?

c# - MaskedTextBox 的多行掩码

c# - 将可运行脚本添加到 ASP.NET Core 应用程序

javascript - 使用 .NET 中的 JavaScript 确定 pageLoad() 中是否发生了部分回发以及发生了哪些部分回发