2010-11-18 19 views
15

Sé que esta pregunta se ha hecho miles de veces, y he luchado con él antes, pero por alguna razón, no puedo lograr lo que quiero lograr ... I tener un LinkButton agregado dinámicamente que al hacer clic agregará dinámicamente un control (en este ejemplo, un cuadro de texto) al mismo panel. La intención es agregar continuamente tantos controles como las veces que se hizo clic en LinkButton (es decir, hago clic una vez, un cuadro, luego otro clic me dará dos cuadros, otro clic agrega un tercero). En el siguiente código, utilizo la fecha y hora actuales serializadas para crear una ID única para cada control de cuadro de texto.ASP.NET crea dinámicamente controles y devolución de datos

Cuando ejecuto el código, haciendo clic en "Añadir filtro" generará un nuevo cuadro de texto, pero una vez que se hace clic de nuevo va a crear una nueva, y disponer de la anterior. En cambio, quiero persistir en el cuadro de texto anterior, así como en los datos enviados dentro de él.

Su ayuda es apreciada.

En el aspx:

<asp:Panel ID="pnlFilter" runat="server"> 

</asp:Panel> 

En los aspx.cs:

protected void Page_Init(object sender, EventArgs e) 
{ 
     LinkButton lb = new LinkButton(); 
     lb.ID = "lbAddFilter"; 
     pnlFilter.Controls.Add(lb); 
     lb.Text = "Add Filter"; 
     lb.Click += new EventHandler(lbAddFilter_Click); 
} 


void lbAddFilter_Click(object sender, EventArgs e) 
{ 
    TextBox tb = new TextBox(); 
    tb.ID = "tb" + DateTime.Now.ToBinary().ToString(); 
    pnlFilter.Controls.Add(tb); 
} 

Respuesta

16

Para cualquier otra persona que intente hacer algo como esto: no lo haga. En cambio, piense en el flujo de información y comprenda que hay una mejor manera de hacerlo. Los controles de entrada no necesitan ser creados dinámicamente. Pueden ser estáticos, y al completar y enviar en uno, esa información tiene que ir a alguna parte (base de datos, caché, sesión, por ejemplo). Una vez que esté allí, en la devolución de datos, recorra todos los elementos en su almacenamiento de elección y cree una pantalla para ellos.

Eso es lo que he hecho y me ha hecho la vida mucho más fácil. Espero que ayude a alguien.

+0

¿Qué harías en una situación en la que se creen cuestionarios (encuestas) en una determinada aplicación y se presenten a través de un servicio web en el que el sitio web obtiene una encuesta y muestra los campos para ella? en ese caso la creación dinámica de contenido es la única opción adecuada no? – Sander

+0

Sí, crear dinámicamente el contenido está en orden, pero no tiene que ser incremental como lo estaba tratando de hacer; Supongo que su servicio web devuelve todos los resultados cada vez, en cuyo caso los renueva todos. Con el uso de ViewState y el almacenamiento en caché, su rendimiento debería ser bastante bueno. –

+1

Eres un genio. Estaba tratando de lograr lo mismo que el OP, pero esto me hizo darme cuenta de que puedo en lugar de agregar varias instancias de control, puedo mostrar el nuevo control en una ventana modal y en "guardar" en su modal, comprometerme con el almacén de datos y luego carga eso en la página muy fácilmente. Mil gracias. He pasado 3 días y toda esta noche tratando de resolver esto. –

0

Trate de añadir,

if(!Page.IsPostback) 
    --- your code that adds different controls. 
+0

Envolví todo dentro de Page_Init en el! IsPostBack si. Al hacerlo, cargué los botones de enlace y el estado inicial de la página, pero cuando hago clic en uno de esos botones de enlace, todos desaparecen y no hay nada en la página. –

1

creo que tendrá que volver a crear cada control cada devolución.

sé que el control almacena repetidor suficiente información sobre sus hijos para recrear ellos cuando databound ... Usted puede ser capaz de utilizarlo para guardar un poco de trabajo.

+0

Debe recrearlos en cada devolución de datos es correcto. En algún lugar necesita almacenar cuántos ya tiene. Tal vez en Viewstate o algo así. – Remy

11
void lbAddFilter_Click(object sender, EventArgs e) 
{ 
    TextBox tb = new TextBox(); 
    tb.ID = "tb" + DateTime.Now.ToBinary().ToString(); 
    pnlFilter.Controls.Add(tb); 
} 

Eso no va a funcionar, es un problema de ciclo de vida como lo dedujo en su pregunta. Hay muchas formas de trabajar con esto, pero la sugerencia de Honus Wagner es la más flexible.

Lo que sucede aquí es que está llamando Controles.Agregar en el controlador de eventos y el control se agrega a la lista de control y en la siguiente solicitud (ya sea una devolución parcial, una devolución total o una página nueva)), ese control se ha ido porque no lo has persistido en ningún lado.

Esto es lo que está pasando en su página de ciclo de vida del evento en este momento:

  1. Página llama OnInit y añade su LinkButton
  2. El usuario hace clic en el LinkButton
  3. Página llama OnInit para iniciar la solicitud de devolución de datos.El LinkButton se recrea
  4. El controlador de eventos se llama, que crea dinámicamente el cuadro de texto y lo añade a la colección de controles
  5. el usuario hace clic en el nuevo LinkButton
  6. Página llama OnInit para añadir el LinkButton nuevo. La colección pnlFilter.Controls está vacía en este momento, a excepción de los elementos que haya declarado estáticamente en su marcado.
  7. Se llama al controlador de eventos y se agrega un nuevo cuadro de texto a la lista de control.

no estoy seguro de que es la mejor práctica, pero he tenido éxito con un modelo similar a este (tenga en cuenta que no he probado este código - puede necesitar un ajuste):

protected override void OnInit(EventArgs e) 
{ 
    base.OnInit(e); 

    LinkButton lb = new LinkButton(); 
    lb.ID = "lbAddFilter"; 
    pnlFilter.Controls.Add(lb); 
    lb.Text = "Add Filter"; 
    lb.Click += new EventHandler(lbAddFilter_Click); 

    // regenerate dynamically created controls 
    foreach (var control in PersistedControls) 
    { 
     pnlFilter.Controls.Add(GenerateControl(control)); 
    } 
} 

private IList<Control> _persistedControls; 
private const string PersistedControlsSessionKey = "thispage_persistedcontrols"; 
private IList<Control> PersistedControls 
{ 
    if (_persistedControls == null) 
    { 
     if (Session[PersistedControlsSessionKey] == null) 
      Session[PersistedControlsSessionKey] = new List<Control>(); 
     _persistedControls = Session[PersistedControlsSessionKey] as IList<Control>; 
    } 
    return _persistedControls; 
}  

void lbAddFilter_Click(object sender, EventArgs e) 
{ 
    TextBox tb = new TextBox(); 
    tb.ID = "tb" + DateTime.Now.ToBinary().ToString(); 
    PersistedControls.Add(tb); 
    pnlFilter.Controls.Add(tb); 
} 

Tenga en cuenta que no estoy seguro acerca de agregar objetos de control reales al almacén de sesiones: creo que hay problemas con los ID de control que causarán errores en la devolución (¿quizás un control no es serializable?). En la solución que desarrollé, generé un nuevo TextBox/Label/ComboBox/etc en mi equivalente del método GenerateControl, y almacené una clase de contenedor personalizada en la colección PersistedControls que contenía las diversas propiedades del control de UI que necesitaría generar en cada página Init.

Cuestiones relacionadas