2011-02-09 18 views
5

A pesar de trabajar con WebForms durante años, todavía me encuentro confundido sobre el ciclo de vida del evento de vez en cuando. No se trata tanto de un problema que deba resolverse, sino de una mejor comprensión de por qué las cosas funcionan de la manera en que lo hacen.¿Por qué los subcontroles se inicializan antes que sus contenedores?

Suponga que tiene una forma:

Default.aspx:

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

UserControl1: ascx:

<MyControls:UserControl2 runat="server"> 

Los OnInit eventos ocurren en este orden:

UserControl2_OnInit 
UserControl1_OnInit 
Default_OnInit 

¿No es esto solo un bajo-ackwards? ¿No debería ejecutarse el código Init en el orden en que se crean los controles? ¿No debería un control principal poder inicializar las propiedades de un niño antes de que se ejecute OnInit? Es decir, aunque puede inicializar las propiedades de los subcontroles en el marcado, no hay una forma directa de que un control principal pueda establecer dinámicamente las propiedades del control secundario que estará disponible para su evento OnInit.

Lo que he terminado haciendo es cosas como esta:

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 
} 

así que no es un problema insuperable. Simplemente no entiendo por qué es un problema en primer lugar.

Me di cuenta de que tal vez es posible que desee tener todos sus controles secundarios inicializados en su código OnInit. Tan bien, debería poder llamar a base.OnInit primero, en lugar de después, a su propio código de inicialización, que debería hacer que se ejecuten todos los eventos OnInit de control infantil. Pero el ciclo de vida del evento no funciona de esa manera. Los eventos Init no están encadenados recursivamente, parecen funcionar de forma independiente los eventos principales, y el más interno siempre se ejecuta primero. Pero parece que la vida sería mucho más fácil si simplemente estuvieran encadenados de manera recursiva, por lo que podría llamar al evento base (o no) antes de que haga lo suyo en cualquier situación dada. ¿Hay algo que me falta que hace que esta situación aparentemente contra intuitiva sea deseable o incluso necesaria?

+0

Estoy de acuerdo contigo ya que las clases base se inicializan antes que sus hijos. –

+2

No tengo una respuesta a su pregunta, pero puedo decirle que las pautas son que no debe confiar en contenedores para padres o niños en esta etapa del ciclo de vida. http://msdn.microsoft.com/en-us/library/system.web.ui.control.init.aspx –

+0

Esto se reduce a lo que creo que es un defecto de diseño fundamental en la arquitectura de formularios web. Entonces no se supone que establezcas relaciones entre los controles padre e hijo hasta (supongo) 'OnLoad'. Sin embargo, a menudo es importante hacer cosas antes de 'OnLoad', como los controles de recreación que se han creado dinámicamente (lo que MS dice que hacer en OnInit: http://support.microsoft.com/kb/317794 Entonces, ¿qué sucede si necesita información? desde la base de datos para averiguar cuál de esos controles crear? Entonces, ¿qué pasa si tu fuente de datos es determinada por un padre? –

Respuesta

2

This document debería ser la principal fuente de verdad para sus preguntas sobre el ciclo de vida.

Básicamente, OnInit dispara después de la inicialización interna de un control en terminado. Como el control de página es el primer control inicializado, y durante su inicialización inicial, inicializa todos los subcontroles (tal vez en el orden que le da el archivo Designer.cs), entonces tiene sentido que el evento OnInit de la página sea el último llamado , ya que no se ha terminado de inicializar hasta que se hayan inicializado todos sus subcontroles y se hayan activado sus eventos OnInit.Gráficamente, se ve así:

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 

Así orden de INITs en este caso es:

  1. sub-sub-Control3 OnInit
  2. Sub-control1 OnInit
  3. Sub-control2 OnInit
  4. Página OnInit

carga también funcionan de manera similar. En general, debe tratar la mayoría de los eventos como si el control fuera primero su proceso interno (que incluye llamar al mismo evento en todos los subcontroles), y luego desencadenar su código personalizado de manejo de eventos posteriormente.

La mayoría de los ejemplos que usted encuentra usan Page_Load específicamente porque ese debería ser el último evento llamado en esa fase (y es después de que se carguen los datos posteriores). No funcionaría muy bien que se llame primero a Page_Load y se corre el riesgo de tener controles que no estén completamente cargados para su código de manejo de eventos personalizado.

1

La mentalidad de asp.net matriz controla & niño es:

Los padres saben todo acerca de sus hijos, pero los niños saben nada acerca de su padre.

Esta forma de pensar tiene sentido para los controles de servidor reutilizables. La reutilización necesita el control infantil personalizado sin suposiciones sobre la página en la que se utiliza.

El fragmento que usted da me hace adivinar que los controles de usuario de su hijo no están destinados a ser reutilizables como tales; sino que son controles especializados que utiliza para analizar las complejidades de una gran interfaz de usuario engañosa &?

En este caso yo quisiera todavía trato de trabajar con la mentalidad de que "los niños no saben nada sobre sus padres". Piense en http://www.google.co.uk/search?q=gof+mediator+pattern donde la página primaria es el mediador entre sus hijos (la página wikipedia es buena).

¿Pero sus hijos todavía necesitan saber algo sobre el derecho de los padres, porque están haciendo interacciones de UI complejas? Puede abordar esto con interfaces. Cada niño depende no del padre, sino de una interfaz que define exactamente a qué necesitan acceder los niños. Como dice http://en.wikipedia.org/wiki/SOLID, 'depende de las abstracciones, no de las concreciones'. HACER una interfaz por control secundario: 'muchas interfaces específicas del cliente son mejores que una interfaz de propósito general'

Pero todo termina pareciendo sobrediseñado, ¿no? Resulta que una interfaz de usuario con componentes en la que los componentes deben interactuar, solo es complejo, y los componentes pueden resultar grandes y torpes. Este fue, en mi opinión, una de las razones para que los formularios web de la MS ajax controlen perder a jQuery & c. incluso antes de vino MVC.

Agregue a esto que los formularios web ui son muy difíciles de probar por unidad; y su confianza en las inmersiones de calidad de su software.

Recomiendo: Si puede, escape a una reescritura en MVC. Si no puede, considere abandonar los controles del lado del servidor que hacen el comportamiento del lado del cliente, y use jQuery en su lugar. Si no puede hacer eso, simplifique simplifique la interfaz de usuario. Incluso si eso lo hace menos funcional. Si no quiere eso, entonces sus elecciones son: pagar los gastos de ingeniería de la IU; o pagar el gasto de no diseñarlo bien.

+0

En verdad, hago más o menos lo que dices: evita formas web. Desafortunadamente sigue apareciendo en el código heredado - incluso cuando mi q. tiene más de un año. Pero los detalles de mi pregunta no implican que un niño tenga ningún conocimiento de su padre. Quería saber por qué un niño inicializa * antes de * su padre. El conocimiento de es childs, no tiene la oportunidad de básicamente inyectar dependencias antes de que se cree en webforms. La construcción que creé involucra a un niño refiriéndose a su padre, pero solo como un mecanismo para permitir que su padre tenga acceso a un constructor. –

+0

Igual aquí . Los formularios web estar con nosotros durante años. Así es como me topé con esta Q, estaba buscando temas de control del ciclo de vida para obtener ayuda sobre hasta dónde podía instanciar y probar una página en una prueba unitaria. Me quedé atrapado en los controles de niños. Pero, ¿no es querer inyectar algo en el constructor hijo, un síntoma de que el niño necesita saber algo sobre su entorno? –

+0

Tal vez estoy malinterpretando su punto acerca del "medio ambiente" Quiero decir, 'sum (a, b)' es una clase que necesita saber las dos cosas que va a sumar. Pero se proporciona esa información en la construcción; no lo pide desde algo fuera de sí mismo. No puede hacer eso incluso con un control de usuario, excepto en la forma de propiedades de tiempo de compilación aprobadas en su marcado. Entonces, si básicamente significa que "el usuario no debe poder configurar el control del usuario", entonces ... así es ... pero ese no es un principio SÓLIDO. Simplemente los hace menos útiles. –

Cuestiones relacionadas