2010-11-03 30 views
5

Quiero crear un control que permita al usuario diseñar su propia estructura de sitio web. Me imaginaba que dentro de UpdatePanel es control (es) con TextBox (para el nombre de la página) y Button 'agregar debajo'. Que se parecería a:¿Controles dinámicos creados dentro de UpdatePanel?

| "Questions" | 
| [ add below ] | 

|  "Tags" | 
| [ add below ] | 

| "Badges" | 
| [ add below ] | 

ahora, cuando el usuario haga clic en el botón en el elemento "etiquetas" no debería aparecer uno nuevo, entre las "etiquetas" y "Pin", con el nombre editable, por lo que el usuario puede nombrarlo "Usuarios" por ejemplo. Se debe hacer sin la devolución de datos completa (para evitar el parpadeo de la página).

Ahora es mi problema: no puedo cargar esos controles (al menos no todos) en onInit ya que no existen, pero tengo que atender a su clic, así que debería adjuntar el oyente de eventos lo que debería hacerse durante Init fase. ¿Cómo puedo lograr la funcionalidad descrita?

Jugué por mucho tiempo y estoy confundido. Agradecería cualquier consejo.

Respuesta

12

Esta es una situación complicada porque se trata de controles dinámicos que necesita para completarlos en la página init para persistir viewstate, también eventos para controles ad Dedicado dentro de un panel de actualización durante los clics de botón no parece registrarse hasta la próxima devolución de datos, por lo que el evento de clic de botón normal solo se activa una vez cada vez que hace clic en un control recién agregado. Puede haber alguna otra forma de evitar esto que la forma en que lo hice. Si alguien sabe, me gustaría averiguarlo.

Mi solución es mantener una lista de lo que ha agregado dinámicamente y almacenarla en una variable de sesión (porque viewstate no se carga durante el inicio de la página). Luego, en la página init, carga cualquier control que hayas agregado previamente. A continuación, gestione el evento de clic durante la carga de la página con algún código personalizado en su lugar o el evento de clic normal.

He creado una página de muestra para ayudar a probar esto.

Aquí es el código de la página aspx (default.aspx):

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head id="Head1" runat="server"> 
    <title></title> 
</head> 
<body> 
    <form id="form1" runat="server"> 
    <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager> 
    <p>This only updates on full postbacks: <%= DateTime.Now.ToLongTimeString() %></p> 
    <asp:UpdatePanel ID="UpdatePanel1" runat="server"> 
     <ContentTemplate> 
      <asp:PlaceHolder ID="PlaceholderControls" runat="server"></asp:PlaceHolder> 
     </ContentTemplate> 
    </asp:UpdatePanel> 
    </form> 
</body> 
</html> 

Y aquí está el código para el código detrás de la página (default.aspx.cs):

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.UI; 
using System.Web.UI.WebControls; 

public partial class _Default : System.Web.UI.Page 
{ 
    /// <summary> 
    /// this is a list for storing the id's of dynamic controls 
    /// I have to put this in the session because the viewstate is not 
    /// loaded in the page init where we need to use it 
    /// </summary> 
    public List<string> DynamicControls 
    { 
     get 
     { 
      return (List<string>)Session["DynamicControls"]; 
     } 
     set 
     { 
      Session["DynamicControls"] = value; 
     } 
    } 

    protected void Page_Init(object sender, EventArgs e) 
    { 
     PlaceholderControls.Controls.Clear(); 

     //add one button to top that will cause a full postback to test persisting values-- 
     Button btnFullPostback = new Button(); 
     btnFullPostback.Text = "Cause Full Postback"; 
     btnFullPostback.ID = "btnFullPostback"; 
     PlaceholderControls.Controls.Add(btnFullPostback); 

     PlaceholderControls.Controls.Add(new LiteralControl("<br />")); 

     PostBackTrigger FullPostbackTrigger = new PostBackTrigger(); 
     FullPostbackTrigger.ControlID = btnFullPostback.ID; 

     UpdatePanel1.Triggers.Add(FullPostbackTrigger); 
     //----------------------------------------------------------------------- 




     if (!IsPostBack) 
     { 
      //add the very first control   
      DynamicControls = new List<string>(); 

      //the DynamicControls list will persist because it is in the session 
      //the viewstate is not loaded yet 
      DynamicControls.Add(AddControls(NextControl)); 

     } 
     else 
     { 
      //we have to reload all the previously loaded controls so they 
      //will have been added to the page before the viewstate loads 
      //so their values will be persisted 
      for (int i = 0; i < DynamicControls.Count; i++) 
      { 
       AddControls(i); 
      } 
     } 


    } 

    protected void Page_Load(object sender, EventArgs e) 
    { 

     if (!IsPostBack) 
     { 
      //we have to increment the initial 
      //control count here here be cause we cannot persit data in the viewstate during 
      //page init 

      NextControl++; 

     } 
     else 
     { 
      HandleAddNextClick();   

     } 

    } 

    /// <summary> 
    /// this function looks to see if the control which caused the postback was one of our 
    /// dynamically added buttons, we have to do this because the update panel seems to interefere 
    /// with the event handler registration. 
    /// </summary> 
    private void HandleAddNextClick() 
    { 
     //did any of our dynamic controls cause the postback if so then handle the event 
     if (Request.Form.AllKeys.Any(key => DynamicControls.Contains(key))) 
     { 
      DynamicControls.Add(AddControls(NextControl)); 
      NextControl++; 
     } 
    } 



    protected void btnAddNext_Command(object sender, CommandEventArgs e) 
    { 
     //this is intentionally left blank we are handling the click in the page load 
     //because the event for controls added dynamically in the click does 
     //not get registered until after a postback, so we have to handle it 
     //manually. I think this has something to do with the update panel, as it works 
     //when not using an update panel, there may be some other workaround I am not aware of 

    } 

    /// <summary> 
    /// variable for holding the number of the next control to be added 
    /// </summary> 
    public int NextControl 
    { 
     get 
     { 
      return ViewState["NextControl"] == null ? 0 : (int)ViewState["NextControl"]; 
     } 
     set 
     { 
      ViewState["NextControl"] = value; 
     } 
    } 


    /// <summary> 
    /// this function dynamically adds a text box, and a button to the placeholder 
    /// it returns the UniqueID of the button, which is later used to find out if the button 
    /// triggered a postback 
    /// </summary> 
    /// <param name="ControlNumber"></param> 
    /// <returns></returns> 
    private string AddControls(int ControlNumber) 
    { 
     //add textbox 
     TextBox txtValue = new TextBox(); 
     txtValue.ID = "txtValue" + ControlNumber; 
     PlaceholderControls.Controls.Add(txtValue); 

     //add button 
     Button btnAddNext = new Button(); 
     btnAddNext.Text = "Add Control " + ControlNumber; 
     btnAddNext.ID = "btnAddNext" + ControlNumber; 
     int NextControl = ControlNumber + 1; 
     btnAddNext.CommandArgument = NextControl.ToString(); 

     btnAddNext.Command += new CommandEventHandler(btnAddNext_Command); 
     PlaceholderControls.Controls.Add(btnAddNext); 

     //add a line break 
     PlaceholderControls.Controls.Add(new LiteralControl("<br />")); 

     return btnAddNext.UniqueID; 

    }  
} 

Avíseme si este código lo ayuda en absoluto. Traté de agregar comentarios con mi comprensión de lo que está sucediendo y cómo funciona.

+0

que será sin duda el registro suyo solución después del trabajo y darle más comentarios. Muchas gracias por la muestra, incluso si no lo pedí! – zgorawski

+0

Funciona como un hechizo :) Olvidé/no sabía sobre algunas características que utilizó, por lo que la solución de la mina estaba incompleta. ¡Muchas gracias! Me ayudaste mucho :) – zgorawski

+0

me alegro de poder ayudar, pero me gustaría que hubiera una manera de hacerlo sin utilizar la sesión, pero no conozco otra forma fácil de almacenar y recuperar información antes de que se cargue viewstate. Probablemente puedas usar campos ocultos o cookies, pero esos parecen incluso tener ideas. Tal vez haya una forma de cargar viewstate manualmente y usarlo en la página init. –

-1

Si desea manejadores de sucesos dinámicos para sus controles, a continuación, puede probar este -

Teniendo en cuenta un control de botón,

Button btnTest = new Button(); 
btnTest .Click += new EventHandler(btnTest_Click); 

usted puede tener su código en el evento de clic de botón,

void btnTest_Click(object sender, EventArgs e) 
{ 
    //your code 
} 
0

esta forma de trabajo para mí

protected void Page_Load(object sender, EventArgs e) 
    { 
     if (Page.IsPostBack) 
     { 
      Button_Click(null, null); 
     } 
    } 

En llamada botón

protected void Button_Click(object sender, EventArgs e) 
    { 
      Panel1.Controls.Clear(); 
      this.YourMethod(); 
     } 
    } 

Antes de llamar al método claro el control de lo contrario se cargará el doble

Cuestiones relacionadas