Этот вопрос касается очень странного поведения веб-элементов управления. Подумайте о следующем, пожалуйста.
Сценарий
У меня есть веб-элемент управления, который используется для отображения некоторых данных. 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
в обычной веб-форме. Эта веб-форма называется 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>
Код этой веб-формы 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();
}
}
проблема
В чем моя проблема ???
Хорошо, когда страница загружается в первый раз, я вижу некоторые данные в виде списка, так что все работает.
Когда я выбираю другую страницу, я заставляю страницу перезагружаться и отправлять обратно ... my ListView
покажет правильное количество записей, но без данных на нем. Веб-элемент управления размещается столько раз, сколько количество извлеченных записей данных, но в веб-элементе управления нет данных.
Результаты отладки
Я провел несколько сеансов отладки, и вот что происходит, пожалуйста, следуйте за мной, это ОЧЕНЬ ВАЖНО понять, я думаю.
Страница загружается впервые
1) Load
выполняется метод страницы.
2) ListView
s ItemDataBound
обработчик событий выполняется. Ну, учитывая, что у меня есть три элемента в массиве Data[]
в DataSource
, обработчик вызывается три раза. Проверяя значения при отладке метода, я вижу, что ((Data)e.Item.DataItem).DataField1
и ((Data)e.Item.DataItem).DataField2
- это правильные значения, полученные из связанного источника данных в ListView
.
После выполнения метода курсор отладчика перемещается в 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
метод страницы выполняется, но он ничего не делает.
2) MyLVPaging_TreeView_SelectedNodeChanged
выполнено. Здесь я вижу, что все имеет правильное значение:
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 =
. ((ДАО) this.ViewState [ "ДАО"]) GetData (); // <- источник данных изменен
} </p>
3) ListView
s ItemDataBound
обработчик событий выполняется. Что ж, здесь при отладке я вижу то же, что и раньше, я имею в виду, что я вижу, что новые значения, новые Data
были связаны с 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.
}
Хорошо !!! ЭТО ПОТЕРЯЕТ ГОСУДАРСТВО И ТАКЖЕ ЦЕННОСТИ
ПРОЙДЕН ИЗ ВИДА СПИСКА
HANDLER !!!!!!!!!
Мой вопрос
Что, черт возьми, происходит ???
Примечания
1) Пожалуйста, не зацикливайтесь на том, как мне удалось связать данные для событий Load
и PreRender
... У меня такое ощущение, что это не ошибка! Я думаю, это связано с жизненным циклом страницы. Однако, если вы считаете, что это важная деталь, дайте мне знать.
2) DAO
и его функция GetData()
- это способ дать вам как можно быстрее понять сценарий, который немного более четко сформулирован, но с той же точной структурой, которую я показал здесь.
Спасибо за вашу помощь.