Na svém posledním ASP.NET kurzu jsem se báječně chytil na jednom primitivním demu na fungování ViewState. Krásně jsem předváděl, jak „ve fázi Init není ještě ViewState trackován, po fázi Init nastává LoadViewState a před tím se zapne jeho tracking – TrackViewState()“, nu což, vyrobil jsem si krásné demo a nestíhal jsem pak chvíli zírat.
(Základy fungování ViewState viz článek Co by měl každý vědět o ViewState.)
„Nefunkční“ demo
Vyrobil jsem primitivní stránku, s jedním Labelem a jedním tlačítkem.
<asp:Label ID="MyLabel" Text="Výchozí text" runat="server" /> <asp:Button ID="MyButton" Text="Postback" runat="server" />
a jak jsem se demonstrovat, jak přiřazení vlastnosti Text ve fázi Init nepřežije postback:
void Page_Init(object sender, EventArgs e) { if (!IsPostBack) { MyLabel.Text = "Nová hodnota z fáze Init!"; } }
Uff, jaké bylo mé překvapení, když Label i po kliknutí na tlačítko Postback přežíval s hodnotou „Nová hodnota z fáze Init!“. Mnohým je hned jasné, kde jsem udělal chybu, ostatním přiblížím:
ViewState v životním cyklu stránek/controlů
Mé překvapení naštěstí netrvalo dlouho, rychle jsem si ověřil, kde přesně se volá v životním cyklu controlů TrackViewState() a rozuzlení bylo na světě:
- TrackViewState() není první operace po fázi Init, nýbrž poslední operace fáze Init samotné,
- fáze Init (jako jediná ze základních fází životního cyklu) probíhá zdola nahoru, procházením stromu control-tree do hloubky – fáze Init nadřazeného controlu je završena až po dokončení fází Init všech jeho child-controls.
Výsledek je tedy nasnadě, v obsluze události Page_Init jsme úplně na vrcholu control-tree a fáze Init jednotlivých controlů již proběhla. Jejich TrackViewState() již proběhl a ViewState controlů tak již sleduje změny jednotlivých hodnot. Nastavení MyLabel.Text ve fází Page_Init tedy již je operací, kdy změny ViewState labelu jsou sledovány, narozdíl od ViewState stránky (Page) samotné, kde ještě TrackViewState() neproběhl.
„Funkční“ demo
Demo jsem rychle opravil a vše krásně fungovalo, jak má:
void MyLabel_Init(object sender, EventArgs e) { if (!Page.IsPostback) { this.Text = "Text nastavený ve fázi Init labelu, nepřežije Postback."; } } void Page_Init(object sender, EventArgs e) { if (!IsPostback) { this.Title = "Title nastavený ve fázi Init page, nepřežije Postback."; } }
Ve fázi Init samotného Labelu ještě jeho TrackViewState() neproběhl, tedy se Text nezachová.
Ve fázi Init stránky už proběhl TrackViewState() controlů, ale stránky samotné ještě ne, tedy třeba Title se nezachová.