Pregunta

Estoy tratando de entender asp.net.Tengo experiencia como desarrollador de PHP desde hace mucho tiempo, pero ahora me enfrento a la tarea de aprender asp.net y estoy teniendo algunos problemas con él.Es muy posible que sea porque estoy tratando de forzar el marco a algo para lo que no está diseñado, por lo que me gustaría aprender cómo hacerlo "de la manera correcta".:-)

Mi problema es cómo agregar controles a una página mediante programación en tiempo de ejecución.Por lo que puedo entender, es necesario crear los controles en page_init, ya que de lo contrario desaparecerán en la siguiente devolución de datos.Pero muchas veces me enfrento al problema de que no sé qué controles agregar en page_init, ya que depende de los valores de la devolución de datos anterior.

Un escenario simple podría ser un formulario con un control desplegable agregado en el diseñador.El menú desplegable está configurado en AutoPostBack.Cuando se produce la devolución de datos, necesito representar uno o más controles dependiendo del valor seleccionado en el control desplegable y preferiblemente hacer que esos controles actúen como si hubieran sido agregados por el diseño (como en "cuando se publique, comportarse" correctamente ").

¿Estoy yendo por el camino equivocado aquí?

¿Fue útil?

Solución

Estoy de acuerdo con los otros puntos planteados aquí "Si puedes dejar de crear controles dinámicamente, entonces hazlo..." (por @Jesper Blad Jenson también conocido como) pero aquí hay un truco que resolví con controles creados dinámicamente en el pasado.

El problema se convierte en la gallina y el huevo.Necesita su ViewState para crear el árbol de control y necesita que se cree su árbol de control para llegar a su ViewState.Bueno, eso es casi correcto.Hay una manera de llegar a los valores de ViewState justo antes el resto del árbol está poblado.Eso es anulando LoadViewState(...) y SaveViewState(...).

En SaveViewState almacene el control que desea crear:

protected override object SaveViewState()
{
    object[] myState = new object[2];
    myState[0] = base.SaveViewState();
    myState[1] = controlPickerDropDown.SelectedValue;

    return myState
}

Cuando el marco llame a su anulación "LoadViewState", obtendrá el objeto exacto que devolvió desde "SaveViewState":

protected override void LoadViewState(object savedState) 
{
    object[] myState = (object[])savedState;

    // Here is the trick, use the value you saved here to create your control tree.
    CreateControlBasedOnDropDownValue(myState[1]);

    // Call the base method to ensure everything works correctly.
    base.LoadViewState(myState[0]);
}

He usado esto con éxito para crear páginas ASP.Net donde se serializó un conjunto de datos en ViewState para almacenar cambios en una cuadrícula completa de datos, lo que permite al usuario realizar múltiples ediciones con PostBacks y finalmente confirmar todos sus cambios en un solo "Guardar". operación.

Otros consejos

Debe agregar su control dentro del evento OnInit y se conservará el estado de visualización.No use if(ispostback), porque los controles deben agregarse cada vez, ¡evento en la devolución de datos!
(Des)La serialización de viewstate ocurre después de OnInit y antes de OnLoad, por lo que su proveedor de persistencia de viewstate verá controles agregados dinámicamente si se agregan en OnInit.

Pero en el escenario que estás describiendo, probablemente la vista múltiple o simplemente ocultar/mostrar (propiedad visible) será una mejor solución.
Es porque en el evento OnInit, cuando debes leer el menú desplegable y agregar nuevos controles, el estado de vista aún no se lee (se deserializa) y no sabes qué eligió el usuario.(puedes hacer request.form(), pero eso se siente un poco mal)

Después de haber luchado con este problema durante un tiempo, se me ocurrieron estas reglas básicas que parecen funcionar, pero YMMV.

  • Utilice controles declarativos siempre que sea posible
  • Utilice el enlace de datos siempre que sea posible
  • Comprender cómo funciona ViewState
  • La propiedad Visibilty puede ser de gran ayuda
  • Si debe usar agregar controles en un controlador de eventos, use el consejo de Aydsman y vuelva a crear los controles en un LoadViewState anulado.

VERDADERAMENTE entender ViewState es una lectura obligada.

Comprender los controles dinámicos con el ejemplo muestra algunas técnicas sobre cómo utilizar el enlace de datos en lugar de controles dinámicos.

Comprender REALMENTE los controles dinámicos También aclara las técnicas que se pueden utilizar para evitar controles dinámicos.

Espero que esto ayude a otros con los mismos problemas.

Si realmente necesita utilizar controles dinámicos, lo siguiente debería funcionar:

  • En OnInit, vuelva a crear exactamente la misma jerarquía de control que estaba en la página cuando se cumplió la solicitud anterior.(Si esta no es la solicitud inicial, por supuesto)
  • Después de OnInit, el marco cargará el estado de vista de la solicitud anterior y todos sus controles deberían estar ahora en un estado estable.
  • En OnLoad, elimine los controles que no sean necesarios y agregue los necesarios.También tendrá que guardar de alguna manera el árbol de control actual en este punto, para usarlo en el primer paso durante la siguiente solicitud.Podría utilizar una variable de sesión que dicte cómo se creó el árbol de control dinámico.Incluso almacené toda la colección de Controles en la sesión una vez (Dejad las horcas a un lado, era sólo para una demostración.).

Volver a agregar los controles "obsoletos" que no necesitará y que se eliminarán en OnLoad de todos modos parece un poco peculiar, pero Asp.Net realmente no fue diseñado teniendo en mente la creación de controles dinámicos.Si no se conserva exactamente la misma jerarquía de controles durante la carga del estado de vista, todo tipo de errores difíciles de encontrar comienzan a acechar en la página, porque los estados de los controles más antiguos se cargan en los recién agregados.

Lea sobre el ciclo de vida de la página Asp.Net y especialmente sobre cómo funciona el estado de vista y quedará claro.

Editar:Este es un muy buen artículo sobre cómo se comporta viewstate y qué debes considerar al tratar con controles dinámicos: http://geekswithblogs.net/FrostRed/archive/2007/02/17/106547.aspx

Bien.Si puede dejar de crear controles dinámicamente, hágalo; de lo contrario, lo que debería hacer es usar Page_Load en lugar de Page_Init, pero en lugar de colocar cosas dentro de If Not IsPostBack, luego configúrelo directamente en el método.

Ah, ese es el problema con la abstracción con fugas de los formularios web ASP.NET.

¿Quizás le interese ver ASP.NET MVC, que se utilizó para la creación de este sitio web stackoverflow.com?Esto debería ser más fácil para usted, ya que tiene experiencia en PHP (por lo tanto, pedalea a fondo cuando se trata de HTML y Javascript).

Creo que la respuesta aquí está en el MultiView control, de modo que, por ejemplo, el menú desplegable cambie entre diferentes vistas en la vista múltiple.

¡Probablemente incluso pueda vincular datos de la propiedad de vista actual de la vista múltiple al valor del menú desplegable!

La única respuesta correcta la dio Aydsman.LoadViewState es el único lugar para agregar controles dinámicos donde sus valores de estado de vista se restaurarán cuando se vuelvan a crear y puede acceder al estado de vista para determinar qué controles agregar.

Me encontré con esto en el libro "Pro ASP.NET 3.5 en C# 2008" en la sección Creación de control dinámico:

Si necesita recrear un control varias veces, debe realizar la creación del control en el controlador de eventos Page.Load.Esto tiene el beneficio adicional de permitirle usar el estado de vista con su control dinámico.Aunque el estado de la vista normalmente se restaura antes del evento Page.Load, si crea un control en el controlador para el evento Page.Load, ASP.NET aplicará cualquier información del estado de la vista que tenga después de que finalice el controlador del evento Page.Load.Este proceso es automático.

No lo he probado, pero podrías investigarlo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top