问题描述
|
这个问题是关于Web控件的一种非常奇怪的行为。请考虑以下内容。
情境
我有一个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;
}
}
好吧,我以普通的Web形式在一个ListView
的矿井中使用此控件。此网络表单称为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>
web8ѭ背后的Web表单代码为:
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
将显示正确的条目数,但其中没有数据。 Web控件的放置次数与检索到的数据记录的数量相同,但是Web控件中没有数据。
调试结果
我进行了一些调试会议,这是发生了什么,请跟我来,我想这非常重要。
首次加载页面
1)执行Load
页面方法。
2)执行ListView
的ItemDataBound
事件处理程序。好吧,假设我在DataSource
的Data[]
数组中有三个元素,则该处理程序被调用了3次。在继续调试该方法时检查值,可以看到((Data)e.Item.DataItem).datafield1
和((Data)e.Item.DataItem).datafield2
是从ListView
中的绑定数据源检索的正确值。
执行该方法后,调试器光标移至控件的Page_Load
方法的MyWebControl.ascx.cs
。通过检查变量,我可以看到发生了这种情况:
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
页面方法,但不执行任何操作。
2)执行MyLVPaging_TreeView_SelectednodeChanged
。在这里,我可以看到所有内容都具有正确的值:
受保护的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 \”]; // <-索引已保存
//设置新索引后,GetData将返回另一组结果
this.MyLV_ListView.DataSource =
((DAO)this.ViewState [\“ DAO \”])。GetData(); // <-数据源已更改
}
3)执行ListView
的ItemDataBound
事件处理程序。好吧,在这里,调试我可以看到与以前相同的意思,我的意思是,我看到新的值,新的Data
已绑定到ListView
,实际上,我可以检查分配给模板项目的新值。
显然,和以前一样,执行该方法后,调试器光标将移至控件的Page_Load
方法的MyWebControl.ascx.cs
。
邪恶:我可以看到以下内容:
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.
}
好!!!它丢失状态和其他值
通过列表视图
处理者!!!!!!!!!
我的问题
这到底是怎么回事???
笔记
1)请不要过多地关注我如何管理Load
和PreRender
事件上的数据绑定...我觉得这不是错误!我想这与页面生命周期有关。但是,如果您认为这很重要,请告诉我。
2)ѭ35和它的功能GetData()
是让您尽可能快地理解场景的一种方法,该场景稍微多了一些,但是结构与我在此处显示的相同。
谢谢您的帮助。
解决方法
从我的评论:
你为什么不动
来自this.MyLV_ListView.DataBind()
预渲染到SelectedNodeChanged?和
为什么需要字段str1和
您的UserControl中的str2?物业
Str1应该获取/设置this.MyLabel1.Text
和属性Str2应该获得/设置
this.MyLabel2.Text,因为
标签\的文本已经存储在
ViewState。
安德烈:
...因此这些设置不是
要在负载中制造?
我:
您不需要等待任何事件
碰巧设置标签的文本。的
属性应直接导致
相应的标签,因此您的
字段str1和str2是冗余的。
他们将被处置在
页面生命周期与
标签的文本属性是
自动存储在ViewState中
跨回发。