Mi sono avventurato nello sviluppo di un Custom Server
Control per ASP.NET abbastanza complesso (almeno per la mia esperienza in questo
campo che è limitata a qualche controllino che non gestiva postback): ho
sviluppato un ConnectionStringBuilder, per inserirlo nelle pagine di
installazione del blogging engine al quale sto contribuendo, SubText.
Ho dovuto affrontare un problema abbastanza sottile: il controllo contiene
dei DropDown che vengono popolati direttamente nella sua prima visualizzazione,
ma sul postback i valori non venivano mantenuti.
Abilitando il Trace ho
notato che il ViewState era sempre di 0 byte.
Invece, il DropDown popolato sul postback manteneva correttamente i valori
caricati.
Ho impiegato parecchio tempo per trovare la soluzione: dopo i primi 15 minuti
su Google non sono riuscito a trovare nessuna menzione del problema, quindi
significa solo due cose:
- è un problema banalissimo e quindi nessuno ne ha mai parlato
- è un problema che quasi nessuno incontra e quindi, nessuno ne
parla
In realtà la risposta sta nel mezzo: pochi sviluppano custom controls
complessi, e la soluzione al problema era ovvia sapendo come funziona il
ViewState.
Una controllo salva il ViewState per tutti i controlli figli, ma solo a
partire dal momento nel quale questi vengono salvati nella collection dei
Controls.
Quindi prima di popolare la dropdown list avrei dovuto collegarla a cascata
fino al controllo principale, non solo al suo parent.
Riporto due snippet trovati sul post di Scott
Mitchell (per Igor, è il fondatore di 4GuysFromRolla ) che mi ha salvato da una figura meschina con i colleghi sviluppatori del progetto SubText.
Cosa ho fatto (e, a quanto pare, ha fatto pure lui) --- ATTENZIONE: E'
SBAGLIATO ---:
public class MyControl : WebControl, INamingContainer
{
...
protected override void CreateChildControls()
{
DropDownList ddl = new DropDownList();
if (!Page.IsPostBack)
// do data binding to some database...
Controls.Add(ddl);
}
}
E come va fatto correttamente
public class MyControl : WebControl, INamingContainer
{
...
protected override void CreateChildControls()
{
DropDownList ddl = new DropDownList();
Controls.Add(ddl); // Add the control FIRST
if (!Page.IsPostBack) // Bind data AFTER
// do data binding to some database...
}
}
Per la spiegazione originale: Control Building and ViewState Lesson for the Day , e Composite controls that do their own
databinding