2011-02-09 8 views
5

Nonostante abbia lavorato con WebForms per anni, continuo a trovarmi confuso sul ciclo di vita degli eventi di tanto in tanto. Questo non è tanto un problema che deve essere risolto, quanto sperare di ottenere una migliore comprensione del perché le cose funzionano come loro.Perché i controlli secondari vengono inizializzati prima dei contenitori?

Supponiamo di avere una forma:

Default.aspx:

<form> 
    <MyControls:UserControl1 runat="server"> 
</form> 

UserControl1: ascx:

<MyControls:UserControl2 runat="server"> 

Gli OnInit eventi si verificano nel seguente ordine:

UserControl2_OnInit 
UserControl1_OnInit 
Default_OnInit 

Non è solo un bass-ackwards? Non dovrebbe essere eseguito il codice Init nell'ordine in cui vengono creati i controlli? Non dovrebbe un controllo genitore essere in grado di inizializzare le proprietà di un figlio prima dell'esecuzione di OnInit? Cioè, mentre è possibile inizializzare le proprietà dei sottocontrolli nel markup, non esiste un modo diretto per consentire a un controllore principale di impostare dinamicamente le proprietà del controllo figlio che saranno disponibili per l'evento OnInit.

Quello che ho finito per fare è cose come questa:

override void UserControl2_OnInit() 
{ 
    NamingContainer.OnInit += new EvenHandler(UserControl1_ActualInit); 
} 
protected void UserControl2_ActualInit(..) { 
    // do actual init code here, which will occur before OnLoad but after it's parent 
    // OnInit 
} 

Quindi non è un problema insormontabile. Solo non capisco perché è un problema, in primo luogo.

Mi rendo conto che forse potresti voler essere in grado di inizializzare tutti i controlli figlio nel tuo codice OnInit. Quindi, dovresti essere in grado di chiamare base.In prima, anziché dopo, il tuo codice di inizializzazione, che dovrebbe causare l'esecuzione di tutti gli eventi OnInit del controllo figlio. Ma il ciclo di vita dell'evento non funziona in questo modo. Gli eventi Init non sono concatenati in modo ricorsivo, sembrano eseguire indipendentemente gli eventi parent e il più interno viene sempre eseguito per primo. Ma sembra che la vita sarebbe molto più facile se fossero semplicemente incatenati in modo ricorsivo in modo da poter chiamare l'evento di base (o meno) prima di fare la tua cosa in una determinata situazione. C'è qualcosa che mi manca che rende questa situazione apparentemente controintuitiva desiderabile o addirittura necessaria?

+0

Sono d'accordo con te poiché le classi base sono inizializzate prima dei loro figli. –

+2

Non ho una risposta alla tua domanda, ma posso dirti che le linee guida sono che non devi fare affidamento sui contenitori genitore o figlio in questa fase del ciclo di vita. http://msdn.microsoft.com/en-us/library/system.web.ui.control.init.aspx –

+0

Si tratta di ciò che ritengo sia un difetto di progettazione fondamentale nell'architettura dei Webform. Quindi non si suppone che si stabiliscano relazioni tra i controlli padre e figlio finché (suppongo) 'OnLoad'. Tuttavia, è spesso importante fare le cose prima di 'OnLoad', come ricreare i controlli che sono stati creati dinamicamente (che ms dice di fare in OnInit: http://support.microsoft.com/kb/317794 Quindi se hai bisogno di informazioni dal database per capire quale di questi controlli creare? Quindi, che cosa succede se la tua origine dati è determinata da un genitore? –

risposta

2

This document dovrebbe essere la principale fonte di verità per le domande sul ciclo di vita.

Fondamentalmente, OnInit genera dopo l'inizializzazione interna di un controllo in terminata. Poiché il controllo della pagina è il primo controllo inizializzato e durante la sua inizializzazione interna inizializza tutti i sottocontrolli (forse nell'ordine dato dal file Designer.cs), allora ha senso che l'evento OnInit della pagina sia l'ultimo chiamato , dal momento che non ha terminato l'inizializzazione finché non vengono inizializzati tutti i sottocontrolli e gli eventi OnInit sono stati attivati.Graficamente, sembra che questo:

Page internal init 
    Sub-control1 internal init 
     Sub-sub-control3 internal init 
     Sub-sub-control3 init finished/OnInit fired 
    Sub-control1 init finished/OnInit fired 
    Sub-control2 internal init 
    Sub-control2 init finished/OnInit fired 
Page init finished/OnInit fired 

Così ordine di INIT in questo caso è:

  1. sub-sub-control3 OnInit
  2. Sotto control1 OnInit
  3. Sotto control2 OnInit
  4. Pagina OnInit

Anche il carico funziona in modo simile. In generale, è necessario trattare la maggior parte degli eventi come se il controllo eseguisse prima il suo processo interno (che include la chiamata dello stesso evento su tutti i sottocontrolli), e successivamente il codice personalizzato per la gestione degli eventi.

La maggior parte degli esempi si trova Page_Load in particolare perché dovrebbe essere l'ultimo evento chiamato in quella fase (ed è dopo che i dati post back vengono caricati). Non funzionerebbe molto bene quando Page_Load viene chiamato per primo e rischia di non avere i controlli in uno stato completamente caricato per il codice di gestione eventi personalizzato.

1

La mentalità per asp.net genitore controlli & bambino è:

genitori sapere tutto di loro bambini, ma i bambini sanno nulla circa il loro genitore.

Questa mentalità ha senso per i controlli server riutilizzabili. La riutilizzabilità ha bisogno del controllo figlio personalizzato che non faccia supposizioni sulla pagina in cui viene usata.

Il frammento che fornisci mi fa intuire che i controlli utente di tuo figlio non sono destinati a essere riutilizzabili come tali; ma piuttosto sono i controlli specializzati che usi per scomporre le complessità di una grande UI &?

In questo caso, vorrei ancora provare a lavorare con la mentalità "i bambini non sanno nulla dei loro genitori". Pensa allo http://www.google.co.uk/search?q=gof+mediator+pattern dove la pagina genitore è il mediatore tra i tuoi figli (la pagina di wikipedia è buona).

Ma i tuoi figli hanno ancora bisogno di sapere qualcosa sul genitore giusto, perché stanno facendo interazioni UI complesse? Puoi affrontarlo con le interfacce. Ogni bambino non dipende dal genitore, ma da un'interfaccia che definisce esattamente a cosa i bambini hanno bisogno di accedere. Come dice http://en.wikipedia.org/wiki/SOLID, 'dipende dalle astrazioni, non dalle concrezioni'. FACCIAMO un'interfaccia per ogni controllo figlio: "molte interfacce specifiche per il cliente sono migliori di un'interfaccia generica" ​​

Ma tutto finisce per sembrare troppo ingegnoso, vero? Si scopre che un'interfaccia utente componentizzata in cui i componenti devono interagire, solo è il complesso ei componenti possono risultare grandi e goffi. Questo era, imho, una delle ragioni per i moduli web di MS che i controlli ajax perdono in jQuery & c. anche prima del MVC è arrivato.

Aggiungete a ciò che i moduli web ui sono molto difficili da testare; e la tua fiducia nelle tue immersioni di qualità del software.

Si consiglia di: Se è possibile, eseguire una riscrittura in MVC. Se non è possibile, si consiglia di abbandonare i controlli sul lato server che eseguono il comportamento clientide e utilizzare invece jQuery. Se non è possibile farlo, semplificare semplificare l'interfaccia utente. Anche se questo lo rende meno funzionale. Se non vuoi che ciò accada, allora le tue scelte sono: paga le spese di ingegnerizzazione dell'interfaccia utente; o pagare la spesa di non ingegneria bene.

+0

In verità, faccio praticamente quello che dici: evita le webform. Sopraggiude ancora il codice legacy - anche se il mio Q. ha più di un anno, ma le specifiche della mia domanda non implicano che un bambino abbia alcuna conoscenza del suo genitore. Volevo sapere perché un bambino inizializza * prima di * suo genitore. la conoscenza di is childs, non ha la possibilità di iniettare fondamentalmente le dipendenze prima che venga creata in webform. Il costrutto che ho creato coinvolge un figlio che si riferisce al suo genitore, ma solo come un meccanismo per consentire al genitore di avere accesso a un costruttore –

+0

Same here . Webforms lo farà essere con noi per anni Ecco come mi sono imbattuto in questo Q, stavo cercando intorno agli argomenti del ciclo di vita del controllo per un aiuto su quanto posso istanziare e testare una pagina in un test unitario. Sono rimasto bloccato sui controlli figlio. Ma - non vuole iniettare qualcosa nel costruttore bambino un sintomo del bambino che ha bisogno di sapere qualcosa sul suo ambiente? –

+0

Forse sto fraintendendo il tuo punto su "ambiente". Voglio dire, 'sum (a, b)' è una classe che ha bisogno di conoscere le due cose che andrà ad aggiungere insieme. Ma è previsto che le informazioni in costruzione; non lo richiede da qualcosa al di fuori di se stesso. Non puoi fare nemmeno quello con un controllo us, tranne nella forma delle proprietà in fase di compilazione passate nel tuo markup. Quindi se fondamentalmente vuoi dire "un controllo utente non dovrebbe essere configurabile in alcun modo da un utente" allora sì ... è così ... ma questo non è un principio SOLIDO. Li rende meno utili. –