这个问题是关于网络控件的一种非常奇怪的行为。请考虑以下内容。
设想
我有一个用于显示一些数据的 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)
ListView
的ItemDataBound
事件处理程序被执行。好吧,假设我在 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)
ListView
的ItemDataBound
事件处理程序被执行。嗯,到这里,调试我可以看到和以前一样,我的意思是,我可以看到新的值,新的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/