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:
5 Comments Filed Under [ ASP.NET 2.0 ]

Comments

# re: Viewstate e controlli dinamici
Gravatar Ma che bel tip per ugi... :-D
Left by Lorenzo Barbieri on 16/05/2007 16.34
# re: Viewstate e controlli dinamici
Gravatar Sei quindi la terza persona che conferma quello che sapevo, i controlli dinamici vanno creati nell'init. Il problema è che ho trovato un libro ed alcuni tutorial che fanno vedere il controllo caricato nell'evento load...facendo delle prove ho visto poi che effettivamente funziona lo stesso. L'unica accortezza è inserire i controlli in dei placeholder, perchè altrimenti il ripristino del viewstate viene fatto in maniera errata.

Alk.
Left by Gian Maria on 16/05/2007 16.41
# re: Viewstate e controlli dinamici
Gravatar Beh è un tantino piu complesso di così :)
Nel senso che l'esempio che ha fatto marco (cioè aggiungere dei controlli _direttamente_ alla collezione di controlli senza passare da un placeholder) lo sconsiglio vivamente in ogni caso. I Placeholder sono li apposta per essere usati a questo scopo!
Utilizzando un placeholder, è "ininfluente" il posto in cui carichi il controllo dinamico, basta che lo fai prima del render, dove vengono effettivamente richiamate le proprietà dei controlli (text, items, etc) che andranno a guardarsi il ViewState e si popoleranno di conseguenza....
Ovviamente, anche all'interno del PlaceHolder bisogna rispettare il valore posizionale dei controlli o va tutto a donne di facili costumi :)
Left by Alessandro Ghizzardi on 16/05/2007 16.51
# re: Viewstate e controlli dinamici
Left by simone on 16/05/2007 23.48
# re: Viewstate e controlli dinamici
Gravatar Qualcuno mi sa dire come posso inserire piu HyperLink in un placeholder ma sistemandoli in colonna?
Left by Nello on 17/06/2008 11.20

Leave Your Comment

Title*
Name*
Email (never displayed)
 (will show your gravatar)
Url
Comment*

Please add 5 and 2 and type the answer here:

Preview Your Comment.