2010-11-18 14 views
15

So che questa domanda è stata fatta migliaia di volte, e ho già faticato prima, ma per qualche motivo, non riesco a realizzare ciò che voglio realizzare ... I avere un LinkButton aggiunto dinamicamente che, una volta fatto clic, aggiungerà dinamicamente un controllo (in questo esempio, una casella di testo) allo stesso pannello. L'intento è quello di aggiungere continuamente tanti controlli quanti sono stati cliccati su 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.ASP.NET ha creato dinamicamente controlli e postback

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 vostro aiuto è apprezzato.

Nella aspx:

<asp:Panel ID="pnlFilter" runat="server"> 

</asp:Panel> 

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

risposta

16

Per chiunque altro cerchi di fare qualcosa del genere: non farlo. Invece, pensa al flusso di informazioni e capisci che c'è un modo migliore per farlo. I controlli di input non devono essere creati dinamicamente. 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.

+0

Cosa faresti in una situazione in cui i questionari (sondaggi) vengono creati in una determinata applicazione e presentati attraverso un servizio web il sito Web recupera un sondaggio e ne rende i campi? in tal caso la creazione dinamica di contenuto è l'unica opzione adatta no? – Sander

+0

Sì, la creazione dinamica del contenuto è in ordine, ma non deve essere incrementale come stavo cercando di fare; Presumo che il tuo servizio Web restituisca tutti i risultati ogni volta, nel qual caso li hai ripetuti tutti in ogni momento. Con l'uso di viewstate e il caching, la tua performance dovrebbe essere piuttosto buona. –

+1

Sei un genio. Stavo cercando di ottenere la stessa cosa dell'OP ma questo mi ha fatto capire che posso invece aggiungere più istanze di controllo, posso solo mostrare il nuovo controllo in una finestra modale e su "salva" nella sua modal, impegnarsi nell'archivio dati e quindi caricarlo sulla pagina molto facilmente. Mille grazie. Ho passato 3 giorni e stasera a cercare di capirlo. –

0

Prova ad aggiungere,

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

Ho avvolto tutto all'interno di Page_Init in! IsPostBack if. Facendo ciò caricate i pulsanti di collegamento e lo stato iniziale della pagina, ma quando clicco su uno di quei pulsanti di collegamento, tutti scompaiono e non c'è nulla nella pagina. –

1

credo che sarà necessario ricreare ogni controllo ogni postback.

So che il controllo del ripetitore memorizza abbastanza informazioni sui propri figli per ricrearli quando il database ... Potrebbe essere possibile utilizzarlo per risparmiare un po 'di lavoro.

+0

È necessario ricrearli su ogni postback corretto. Da qualche parte devi memorizzare quanti ne hai già. Forse nel Viewstate o qualcosa del genere. – Remy

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

Non funziona, si tratta di un problema di 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 accadendo qui è che stai chiamando Controls.Add nel gestore eventi e il controllo viene aggiunto all'elenco di controllo e alla successiva richiesta (sia esso un postback parziale, un postback completo o una nuova pagina hit), quel controllo è sparito perché non lo hai persistito da nessuna parte.

Ecco cosa sta succedendo nel vostro ciclo di vita pagina evento in questo momento:

  1. Pagina chiama OnInit e aggiunge il vostro LinkButton
  2. L'utente fa clic sul LinkButton
  3. Pagina chiama OnInit per iniziare la richiesta postback.Il LinkButton è ricreata
  4. Il gestore di eventi viene chiamato, che crea dinamicamente la TextBox e lo aggiunge alla collezione di controllo
  5. L'utente fa clic sul LinkButton nuovo
  6. Pagina chiama OnInit per aggiungere di nuovo 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 (notare che io non ho ancora testato questo codice - potrebbe essere necessario 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<Control> _persistedControls; 
private const string PersistedControlsSessionKey = "thispage_persistedcontrols"; 
private IList<Control> PersistedControls 
{ 
    if (_persistedControls == null) 
    { 
     if (Session[PersistedControlsSessionKey] == null) 
      Session[PersistedControlsSessionKey] = new List<Control>(); 
     _persistedControls = Session[PersistedControlsSessionKey] as IList<Control>; 
    } 
    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); 
} 

Nota che non sono sicuro di aggiungere oggetti di controllo effettivi all'archivio 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 classe contenitore personalizzata nell'insieme PersistedControls che conteneva le varie proprietà del controllo dell'interfaccia utente che avrei dovuto generare su ogni pagina Init.

Problemi correlati