DropDownlists aggiunti dynamicmente non triggersno l’evento SelectedIndexChanged

Ho visto molte cose su questo argomento, ma non riesco a trovare una soluzione. Aggiungo molti elenchi a discesa con un evento ma non triggersno l’evet SelectedIndexChanged. Ecco il codice del creatore di 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); } 

E naturalmente il mio evento:

 public void Status_SelectedIndexChanged(object sender, EventArgs e) { //DO SOMETHING } 

Cosa mi manca?

Questo è un problema comune ed è correlato al ciclo di vita della pagina:

Dai un’occhiata alle seguenti domande:

Fai clic sugli eventi su Array of buttons

L’array di pulsanti scompare dopo l’evento click

Creare dynamicmente un ImageButton

Ora i passaggi fondamentali da ricordare quando si creano i controlli dinamici sono:

  • I controlli dinamici devono essere creati nell’evento PreInit quando non si sta lavorando con una pagina master, se lo si è, quindi creare i controlli nell’evento Init
  • Evita di impostare le proprietà che possono essere modificate in ogni post in questi eventi perché quando lo stato di visualizzazione viene applicato (in un evento post) le proprietà verranno sovrascritte
  • I controlli dinamici devono essere creati ogni volta che la pagina viene pubblicata , evita questo if(!this.IsPostBack) this.CreatemyDynamicControls();
  • Quando crei i controlli negli eventi PreInit o Init , i loro stati verranno automaticamente impostati in un evento post, il che significa che nell’evento LoadComplete controlli conterranno il loro stato anche quando li creerai nuovamente in ogni post e anche quando lo hai fatto non impostare esplicitamente il loro stato. Nota questo comportamento è diverso quando hai a che fare con i controlli creati in fase di progettazione, in tal caso, l’evento in cui è stato impostato lo stato è l’evento Load
  • La sottoscrizione dell’evento deve avvenire prima del PageLoadComplete o non verrà sollevata

Si consideri la seguente descrizione da MSDN

Se i controlli vengono creati dynamicmente in fase di esecuzione o dichiaratamente all’interno di modelli di controlli con associazione a dati, i loro eventi inizialmente non sono sincronizzati con quelli di altri controlli nella pagina. Ad esempio, per un controllo che viene aggiunto in fase di esecuzione, gli eventi Init e Load potrebbero verificarsi molto più tardi nel ciclo di vita della pagina rispetto agli stessi eventi per i controlli creati in modo dichiarativo. Pertanto, dal momento in cui vengono istanziati, i controlli e i controlli aggiunti dynamicmente nei modelli aumentano gli eventi uno dopo l’altro fino a quando non hanno raggiunto l’evento durante il quale è stato aggiunto alla raccolta Controls.

Quanto sopra non è così chiaro per me, ma ho trovato quanto segue. I seguenti TextBox sono creati in fase di progettazione

  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(); } 

A prima vista si potrebbe pensare che in ogni post tutte le caselle di testo vengano aggiornate con la data corrente, ma questo non è il caso, dal momento che sono state create in fase di progettazione seguono strettamente il ciclo di vita della pagina ASP.Net che significa, il loro stato viene sovrascritto dopo gli eventi PreInit e Init , solo il txtDesignTextBox3 viene aggiornato in ogni post perché la sua proprietà Text viene aggiornata dopo che è stato impostato lo stato di visualizzazione (nell’evento Load ).

Ma con i controlli dinamici il comportamento è diverso, ricorda la descrizione di MSDN:

per un controllo che viene aggiunto in fase di esecuzione, gli eventi Init e Load potrebbero verificarsi molto più tardi nel ciclo di vita della pagina

Considera quanto segue:

  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); } 

In questo caso, i controlli si comportano in modo leggermente diverso, in questo caso, in ogni post, i controlli non vengono mai aggiornati, nemmeno i controlli creati nell’evento Load

Il motivo è che i loro eventi del ciclo di vita si verificano molto più tardi nel ciclo di vita della pagina, il che significa che il loro stato viene sovrascritto anche dopo l’evento Load

Per risolvere questo problema, puoi utilizzare l’evento LoadComplete , in questo caso puoi modificare lo stato dei controlli dinamici:

  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); } 

In questo caso, lo stato verrà aggiornato in ogni post.

Tuttavia, LoadComplete che dovresti iscriverti agli eventi di controlli dinamici, prima dell’evento LoadComplete o che non verranno LoadComplete .

… So che odio questo tipo di comportamento, è per questo che amo MVC

Come riferimento rapido per i controlli creati in fase di progettazione: si noti come viene chiamato il metodo LoadViewState dopo gli eventi PreInit e Init ma prima dell’evento Load . L’evento Load è considerato stabile perché in questo caso è ansible accedere allo stato di visualizzazione dei controlli. Si noti inoltre che il metodo RaisePostBackEvent rappresenta l’evento di controllo che ha causato il RaisePostBackEvent , che può essere, SelectedIndexChanged , Click , ecc questo evento viene gestito dopo l’evento Load

inserisci la descrizione dell'immagine qui

Per una specifica dettagliata completa leggere la documentazione del ciclo di vita della pagina MSDN

Di solito ho visto questo causato da un problema del ciclo di vita della pagina. Se il controllo viene creato solo quando viene triggersto un evento, quando l’indice ha cambiato gli eventi, il controllo non esiste per collegarlo al postback.

Esempio:

  1. MyEvent spara. Drop-down creato. Gestore di eventi specificato.
  2. Evento Index Changed triggersto. La pagina si ricarica. Il menu a discesa non viene trovato, non può essere triggersto.

È necessario assicurarsi che il menu a discesa sia stato creato prima di .NET tentativi per gestire l’evento.

Ti manca:
1- Sostituisci SaveViewState
2- Sostituire LoadViewState

Fornisco un codice di esempio per questa domanda. Lo collaudo. È un lavoro.

ASPX:

 

Codice dietro:

 public partial class Default : System.Web.UI.Page { private List values = new List(); 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)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"; } }