2010-11-03 15 views
5

Chcę stworzyć kontrolę, która pozwoli użytkownikowi zaprojektować własną strukturę strony. Wyobrażałem sobie, że wewnątrz UpdatePanel jest kontrola (y) z TextBox (dla nazwy strony) i Button "dodaj poniżej". Byłoby to wygląda:Dynamiczne utworzone formanty wewnątrz UpdatePanel?

| "Questions" | 
| [ add below ] | 

|  "Tags" | 
| [ add below ] | 

| "Badges" | 
| [ add below ] | 

teraz, gdy użytkownik kliknie na przycisk „Tagi” elementu nie powinno pojawić się nowe, między „Etykiety” i „Odznaki” z edycji nazwy, więc użytkownik może nazwać „Użytkownicy” na przykład. Należy to zrobić bez pełnego odświeżenia strony (aby uniknąć mrugnięć strony).

Teraz jest mój problem: nie mogę załadować tych kontrolek (w końcu nie wszystkie) w onInit, ponieważ one nie istnieją, ale muszę wziąć udział w ich zdarzeniu kliknięcia, więc powinienem załączyć detektor zdarzeń, co powinno być zrobione podczas Init faza. Jak mogę uzyskać opisaną funkcjonalność?

Grałem wokół niego przez zbyt długi czas i jestem zdezorientowany. Byłbym wdzięczny za wszelkie wskazówki.

Odpowiedz

12

Jest to trudna sytuacja, ponieważ mamy do czynienia z dynamicznymi kontrolkami, które trzeba wypełnić na stronie init w celu zachowania stanu oglądania, a także zdarzeń związanych z kontrolkami Oddanie do panelu aktualizacji podczas kliknięć przycisku wydaje się nie być rejestrowane aż do następnego odświeżenia, więc zdarzenie normalnego kliknięcia jest uruchamiane tylko raz po każdym kliknięciu nowo dodanego formantu. Być może istnieje inny sposób obejścia tego problemu niż sposób, w jaki to zrobiłem. Jeśli ktokolwiek wie, że chciałbym się dowiedzieć.

Moje rozwiązanie polega na zachowaniu listy dynamicznie dodawanych elementów i zapisaniu ich w zmiennej sesji (ponieważ stan wyświetlania nie jest ładowany podczas init strony). Następnie na stronie init wczytaj wszystkie wcześniej dodane kontrolki. Następnie zajmij się zdarzeniem kliknięcia podczas ładowania strony, korzystając z niestandardowego kodu lub zdarzenia związanego z normalnym kliknięciem.

Utworzono próbną stronę, aby pomóc w przetestowaniu tego.

Oto kod na stronie 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> 

A oto kod do kodu źródłowego strony (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; 

    }  
} 

Daj mi znać, jeśli ten kod w ogóle Ci pomoże. Próbowałem dodawać komentarze z moim zrozumieniem tego, co się dzieje i jak działa.

+0

pewno sprawdzić Yours roztworze po pracy i dać więcej informacji zwrotnych. Wielkie dzięki za próbkę, nawet gdybym nie poprosił o to! – zgorawski

+0

Działa jak urok :) Zapomniałem/nie wiedziałem o kilku funkcjach, których używałeś, więc moje rozwiązanie było niekompletne. Wielkie dzięki! Bardzo mi pomogłeś :) – zgorawski

+0

cieszę się, że mogłem pomóc, żałuję, że nie było sposobu, aby to zrobić bez korzystania z sesji, ale nie znam innego łatwego sposobu przechowywania i pobierania informacji przed załadowaniem stanu oglądania. Prawdopodobnie możesz użyć ukrytych pól lub ciasteczek, ale wydaje się, że nawet nosili pomysły. Być może istnieje sposób ręcznego załadowania stanu wyświetlania i użycia go w init strony. –

-1

Jeśli chcesz dynamicznych EventHandlers dla potrzeb kontroli, to można spróbować -

Biorąc pod uwagę kontrolę przycisk,

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

Możesz mieć swój kod w zdarzeniu przycisk click,

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

ten sposób działa na mnie

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

W zaproszeniu przycisk

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

Zanim zadzwonisz sposób wyczyścić kontrolę inaczej będzie ładować dwa razy

Powiązane problemy