Динамически добавленные DropDownlists не запускаются SelectedIndexChanged Event
Я многое видел по этой теме, но не могу найти решение. Я добавляю множество выпадающих списков с одним событием, но они не запускают SelectedIndexChanged evet. Вот код создателя drplist:
foreach (var row in cmdSelectCats.ExecuteReader())
{
var id = row["ProductCategoryID"].ToString();
var dropDownStatus = new DropDownList {ID = "DrpStatus-" + id};
dropDownStatus.Items.Add(new ListItem("Aktif", "1"));
dropDownStatus.Items.Add(new ListItem("Pasif", "2"));
dropDownStatus.AutoPostBack = true;
dropDownStatus.SelectedIndexChanged += Status_SelectedIndexChanged;
var tableCell = new TableCell();
tableCell.Controls.Add(dropDownStatus);
dropDownStatus.SelectedValue = row["ProductCategoryStatusID"].ToString();
tableRow.Cells.Add(tableCell);
TblCatList.Rows.Add(tableRow);
}
И, конечно же, мое событие:
public void Status_SelectedIndexChanged(object sender, EventArgs e)
{
//DO SOMETHING
}
Что мне не хватает?
3 ответа
Это общая проблема, связанная с жизненным циклом страницы:
Взгляните на следующие вопросы:
События кликов на массиве кнопок
Массив кнопок исчезает после нажатия кнопки
Динамически создать ImageButton
Теперь основные шаги, которые нужно помнить при создании динамических элементов управления:
- Динамические элементы управления должны быть созданы в
PreInit
Если вы не работаете с главной страницей, создайте элементы управления вInit
событие - Избегайте установки свойств, которые можно изменить в каждом сообщении в этих событиях, потому что при применении состояния просмотра (в событии поста) свойства будут переопределены
- Динамические элементы управления должны создаваться при каждой публикации страницы, избегайте этого
if(!this.IsPostBack) this.CreatemyDynamicControls();
- Когда вы создаете элементы управления в
PreInit
или жеInit
события, их состояния будут автоматически установлены в пост-событии, что означает вLoadComplete
Если ваши элементы управления будут содержать их состояние обратно, даже когда вы создадите их снова в каждом сообщении, и даже если вы явно не установили их состояние. Обратите внимание, что это поведение отличается, когда вы имеете дело с элементами управления, созданными во время разработки, в этом случае событие, в котором было установлено состояние, является событием Load - Подписка на событие должна произойти до
PageLoadComplete
или они не будут подняты
Рассмотрим следующее описание из MSDN
Если элементы управления создаются динамически во время выполнения или декларативно в шаблонах элементов управления с привязкой к данным, их события изначально не синхронизируются с событиями других элементов управления на странице. Например, для элемента управления, который добавляется во время выполнения, события Init и Load могут происходить намного позже в жизненном цикле страницы, чем те же события для элементов управления, созданных декларативно. Следовательно, с момента создания экземпляров динамически добавленные элементы управления и элементы управления в шаблонах повышают свои события один за другим, пока не обнаружат событие, во время которого они были добавлены в коллекцию элементов управления.
Вышесказанное мне не так понятно, но я обнаружил следующее. Следующие TextBox
создаются во время разработки
protected void Page_PreInit(object sender, EventArgs e)
{
this.txtDesignTextBox1.Text = "From PreInit";
this.txtDesignTextBox1.Text += DateTime.Now.ToString();
}
protected void Page_Init(object sender, EventArgs e)
{
this.txtDesignTextBox2.Text = "From Init";
this.txtDesignTextBox2.Text += DateTime.Now.ToString();
}
protected void Page_Load(object sender, EventArgs e)
{
this.txtDesignTextBox3.Text = "From Load";
this.txtDesignTextBox3.Text += DateTime.Now.ToString();
}
На первый взгляд вы можете подумать, что в каждом сообщении все текстовые поля обновляются с текущей датой, но это не так, поскольку они были созданы во время разработки и строго следуют жизненному циклу страницы ASP.Net, что означает их состояние. переопределяется после событий PreInit и Init, только txtDesignTextBox3
обновляется в каждом сообщении, потому что его Text
свойство обновляется после установки состояния просмотра (в Load
событие).
Но с динамическими элементами управления поведение отличается, помните описание MSDN:
для элемента управления, добавляемого во время выполнения, события Init и Load могут происходить намного позже в жизненном цикле страницы.
Учтите следующее:
protected void Page_PreInit(object sender, EventArgs e)
{
var textBox = new TextBox { Text = "From PreInit", Width = new Unit("100%") };
textBox.Text += DateTime.Now.ToString();
this.myPlaceHolder.Controls.Add(textBox);
}
protected void Page_Init(object sender, EventArgs e)
{
var textBox = new TextBox { Text = "From Init", Width = new Unit("100%") };
textBox.Text += DateTime.Now.ToString();
this.myPlaceHolder.Controls.Add(textBox);
}
protected void Page_Load(object sender, EventArgs e)
{
var textBox = new TextBox { Text = "From Load", Width = new Unit("100%") };
textBox.Text += DateTime.Now.ToString();
this.myPlaceHolder.Controls.Add(textBox);
}
В этом случае элементы управления ведут себя немного иначе, в этом случае в каждом сообщении элементы управления никогда не обновляются, даже элементы управления, созданные в Load
событие
Причина в том, что их события жизненного цикла происходят намного позже в жизненном цикле страницы, что означает, что их состояние переопределяется даже после события Load.
Чтобы решить эту проблему, вы можете использовать LoadComplete
событие, в этом случае вы можете изменить состояние динамических элементов управления:
protected void Page_LoadComplete(object sender, EventArgs e)
{
var textBox = new TextBox { Text = "From LoadComplete", Width = new Unit("100%") };
textBox.Text += DateTime.Now.ToString();
this.myPlaceHolder.Controls.Add(textBox);
}
В этом случае состояние будет обновляться в каждом посте.
Однако примите во внимание, что вы должны подписаться на события динамического управления, до LoadComplete
событие или они не будут подняты.
... Я знаю, что ненавижу такое поведение, поэтому я люблю MVC
В качестве краткого справочного материала для элементов управления, созданных во время разработки: обратите внимание на LoadViewState
метод вызывается после PreInit
а также Init
события, но до Load
событие. Load
Событие считается стабильным, поскольку в этом случае вы можете получить доступ к состоянию просмотра ваших элементов управления. Также обратите внимание, что RaisePostBackEvent
метод представляет управляющее событие, которое вызвало пост обратно, это может быть, SelectedIndexChanged
, Click
и т. д. это событие обрабатывается после Load
событие
Для получения полной подробной спецификации прочитайте документацию по жизненному циклу страницы MSDN.
Я обычно видел это, вызванное проблемой жизненного цикла страницы. Если элемент управления создается только при возникновении события, то при срабатывании события с измененным индексом элемент управления не существует, чтобы связать его с обратной передачей.
Пример:
- MyEvent горит. Выпадающий создан. Указан обработчик событий.
- Индекс измененного события сработал. Страница перезагружается. Выпадающий не найден, не может стрелять.
Вы должны убедиться, что раскрывающийся список создан, прежде чем.NET попытается обработать событие.
Вам не хватает:
1- переопределить SaveViewState
2- Переопределить LoadViewState
Я предоставляю пример кода для этого вопроса. Я проверяю это. Это работает.
ASPX:
<form id="form1" runat="server">
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
<div id="myDiv" runat="server">
</div>
<asp:Label ID="lblDescription" runat="server"></asp:Label>
</form>
Код позади:
public partial class Default : System.Web.UI.Page
{
private List<string> values = new List<string>();
protected void Page_Load(object sender, EventArgs e)
{
}
protected override object SaveViewState()
{
object baseState = base.SaveViewState();
object[] allStates = new object[2];
allStates[0] = baseState;
allStates[1] = values;
return allStates;
}
protected override void LoadViewState(object savedState)
{
object[] myState = (object[])savedState;
if (myState[0] != null)
base.LoadViewState(myState[0]);
if (myState[1] != null)
{
values = (List<string>)myState[1];
MyRender();
}
}
protected void Button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
DropDownList ddl = new DropDownList();
ddl.ID = "ClientID" + i;
ddl.Items.Add("Item 1");
ddl.Items.Add("Item 2");
ddl.AutoPostBack = true;
values.Add(ddl.SelectedValue);
myDiv.Controls.Add(ddl);
}
}
private void MyRender()
{
for (int i = 0; i < values.Count; i++)
{
DropDownList ddl = new DropDownList();
ddl.ID = "ClientID" + i;
ddl.Items.Add("Item 1");
ddl.Items.Add("Item 2");
ddl.AutoPostBack = true;
ddl.SelectedIndexChanged += new EventHandler(ddl_SelectedIndexChanged);
myDiv.Controls.Add(ddl);
}
}
void ddl_SelectedIndexChanged(object sender, EventArgs e)
{
lblDescription.Text = ((DropDownList)sender).ID + ": Selected Index Changed";
}
}