Crad's .NET Blog

L'UGIblog di Marco De Sanctis
posts - 190, comments - 457, trackbacks - 70

Viewstate e controlli dinamici

Volevo rispondere a questo post di Gian Maria, poi il testo era un po' lungo e allora ho optato per la modalità stand alone :D

Anche in ASP.NET 2.0, come accadeva nella 1.1, è necessario ricreare controlli dinamici durante la fase di Init al fine di preservare correttamente il viewstate. La ragione risiede nel fatto che il ripristino dello stato dei controlli avviene in maniera posizionale. Consideriamo una pagina con una DropDownList (il cui contenuto è ripristinato tramite Viewstate) e il seguente snippet di codice, che aggiunge un button prima della ddl stessa:

protected void Page_Load(object sender, EventArgs e) { this.form1.Controls.AddAt(0, new Button()); if (!IsPostBack) { ddlTest.DataSource = getDataSource(); ddlTest.DataBind(); } }

Se analizziamo il ciclo di vita della pagina, ad esempio attivando il trace, notiamo che l'ordine degli eventi è il seguente (ho volutamente omesso tutto ciò che non interessa questo discorso):

  1. Init
  2. LoadViewState
  3. Load
  4. SaveViewState

Bene. Visualizziamo nel browser la nostra pagina, LoadViewState non viene sollevato perché non siamo in un postback, Load costruisce il button dinamico, SaveViewState salva lo stato di un albero di oggetti che, grossomodo è

  • Button
  • DropDownList

Supponiamo di effettuare un postback. Cosa accade?

LoadViewState prova a ripristinare lo stato del Button, ma questo ancora non esiste: l'evento Load ancora non si è verificato e l'albero degli oggetti ora è composto dalla sola DropDownList! Il risultato è che LoadViewState invierà i dati del Button al metodo LoadViewState della DropDownList, che ovviamente non sarà in grado di ripristinare correttamente lo stato, proponendoci nel postback una DropDownList vuota.

Creando il button in fase di Init, invece, il problema non si pone, dato che LoadViewState opera in un contesto coerente con quello in cui è stato eseguito il SaveViewState al precedente rendering della pagina.

EDIT: quanto segue è frutto di uno sforzo congiunto da parte mia e del buon Alk :)

In ASP.NET 2.0 (devo verificare cosa accade su 1.1) in realtà è comunque possibile aggiungere controlli dinamici in una fase successiva al LoadViewState: basta utilizzare un placeholder o un qualunque altro controllo contenitore. Come è possibile?

In fase di postback, la Form ripartisce di nuovo il viewstate tra i suoi controlli di primo livello, al PlaceHolder va una porzione di albero e alla DDL un'altra. Quest'ultima, quindi, non si accorge minimamente dell'esistenza di controlli dinamici, riceve dati corretti e può quindi ripristinare il suo stato.

La cosa che sulle prime mi ha sbalordito, è che anche i controlli aggiunti in seguito nel placeholder conservano le informazioni di stato. Non mi spiegavo come ciò fosse possibile, dato che comunque essi vengono creati dopo la fase di LoadViewState. La risposta sta nella classe ControlCollection. Quando viene ripristinato lo stato, un oggetto Control effettua un caching della porzione di viewstate ad esso inviato dal suo contenitore. All'aggiunta di un controllo child

this.plcHolder.Controls.Add(new Button());

viene eseguito il metodo Control.AddedControl che, nel caso la cache interna del viewstate non sia vuota, forza un nuovo Load dello stato per il controllo child (eventualmente anche per Id e non più in base all'ordine).

 

Technorati tags:

Print | posted on Wednesday, May 16, 2007 4:27 PM | Filed Under [ ASP.NET 2.0 ]

Powered by:
Powered By Subtext Powered By ASP.NET