ASP.NET ha creato dynamicmente controlli e postback

So che questa domanda è stata posta migliaia di volte, e ci ho già faticato prima, ma per qualche ragione, non riesco a realizzare ciò che voglio ottenere … Ho aggiunto un LinkButton aggiunto in modo dinamico che quando si fa clic aggiungerà dynamicmente un controllo (in questo esempio, una casella di testo) per lo stesso pannello. L’intento è quello di aggiungere continuamente tanti controlli quante volte è stato fatto clic sul pulsante LinkButton (ad esempio, faccio clic una volta, una casella, poi un altro clic mi darà 2 caselle, un altro clic aggiunge un terzo). Nel seguente codice, utilizzo la data e l’ora correnti serializzate per creare un ID univoco per ciascun controllo casella di testo.

Quando eseguo il codice, facendo clic su “Aggiungi filtro” si genera una nuova casella di testo, ma una volta cliccato di nuovo ne creerà uno nuovo e lo smaltirà. Invece, voglio mantenere la casella di testo precedente e tutti i dati inviati al suo interno.

Il tuo aiuto è apprezzato.

Nell’aspx:

  

In aspx.cs:

 protected void Page_Init(object sender, EventArgs e) { LinkButton lb = new LinkButton(); lb.ID = "lbAddFilter"; pnlFilter.Controls.Add(lb); lb.Text = "Add Filter"; lb.Click += new EventHandler(lbAddFilter_Click); } void lbAddFilter_Click(object sender, EventArgs e) { TextBox tb = new TextBox(); tb.ID = "tb" + DateTime.Now.ToBinary().ToString(); pnlFilter.Controls.Add(tb); } 

Per chiunque altro cerchi di fare qualcosa del genere: non farlo. Invece, pensa al stream di informazioni e capisci che c’è un modo migliore per farlo. I controlli di input non devono essere creati dynamicmente. Possono essere statici e, una volta compilati e inviati su uno, tali informazioni devono andare da qualche parte (database, cache, sessione, ad esempio). Una volta lì, sul postback, passa in rassegna tutti gli elementi nel tuo archivio di scelta e crea loro uno schermo.

Questo è quello che ho fatto e ha reso la vita molto più facile. Spero che aiuti qualcuno.

 void lbAddFilter_Click(object sender, EventArgs e) { TextBox tb = new TextBox(); tb.ID = "tb" + DateTime.Now.ToBinary().ToString(); pnlFilter.Controls.Add(tb); } 

Non funzionerà, è un problema del ciclo di vita come hai dedotto nella tua domanda. Ci sono molti modi in cui puoi lavorare con questo, ma il suggerimento di Honus Wagner è il più flessibile.

Quello che sta succedendo qui è che stai chiamando Controls.Add nel gestore di eventi e il controllo è stato aggiunto alla lista di controllo, e alla prossima richiesta (che si tratti di un postback parziale, di un postback completo o di una nuova pagina), quel controllo se n’è andato perché non l’hai persistito da nessuna parte.

Ecco cosa sta succedendo nel ciclo di vita della tua pagina in questo momento:

  1. La pagina chiama OnInit e aggiunge il tuo LinkButton
  2. L’utente fa clic su LinkButton
  3. La pagina chiama OnInit per iniziare la richiesta di postback. Il LinkButton viene ricreato
  4. Viene chiamato il gestore di eventi, che crea dynamicmente il tuo TextBox e lo aggiunge alla raccolta di controlli
  5. L’utente fa nuovamente clic su LinkButton
  6. La pagina chiama OnInit per aggiungere nuovamente il LinkButton. La collezione pnlFilter.Controls è vuota a questo punto, ad eccezione degli elementi che hai dichiarato staticamente nel tuo markup.
  7. Il gestore eventi viene chiamato e un nuovo TextBox viene aggiunto all’elenco di controllo.

Non sono sicuro che sia la migliore pratica, ma ho avuto successo con un modello simile a questo (nota che non ho testato questo codice – potrebbe essere necessario un aggiustamento):

 protected override void OnInit(EventArgs e) { base.OnInit(e); LinkButton lb = new LinkButton(); lb.ID = "lbAddFilter"; pnlFilter.Controls.Add(lb); lb.Text = "Add Filter"; lb.Click += new EventHandler(lbAddFilter_Click); // regenerate dynamically created controls foreach ( var control in PersistedControls ) { pnlFilter.Controls.Add(GenerateControl(control)); } } private IList _persistedControls; private const string PersistedControlsSessionKey = "thispage_persistedcontrols"; private IList PersistedControls { if (_persistedControls == null) { if (Session[PersistedControlsSessionKey] == null) Session[PersistedControlsSessionKey] = new List(); _persistedControls = Session[PersistedControlsSessionKey] as IList; } return _persistedControls; } void lbAddFilter_Click(object sender, EventArgs e) { TextBox tb = new TextBox(); tb.ID = "tb" + DateTime.Now.ToBinary().ToString(); PersistedControls.Add(tb); pnlFilter.Controls.Add(tb); } 

Si noti che non sono sicuro di aggiungere oggetti di controllo effettivi all’archivio di Session: credo che ci siano problemi con gli ID di controllo che causeranno errori nel postback (forse un controllo non è serializzabile?). Nella soluzione che ho sviluppato, ho generato un nuovo TextBox / Label / ComboBox / etc nell’equivalente del metodo GenerateControl e memorizzato una class contenitore personalizzata nell’insieme PersistedControls che conteneva le varie proprietà del controllo dell’interfaccia utente che avrei dovuto generare su ogni pagina Init.

Credo che dovrai ricreare ogni controllo su ogni postback.

So che il controllo del ripetitore memorizza abbastanza informazioni sui suoi figli per ricrearli quando il database … Potresti essere in grado di usarlo per risparmiare un po ‘di lavoro.

Prova ad aggiungere,

 if(!Page.IsPostback) --- your code that adds different controls.