2010-11-18 32 views
15

Ich weiß, dass diese Frage wurde tausend Mal gefragt, und ich habe damit zuvor gekämpft, aber aus irgendeinem Grund kann ich nicht erreichen, was ich erreichen möchte ... Ich Sie haben einen dynamisch hinzugefügten LinkButton, der beim Anklicken dynamisch ein Steuerelement (in diesem Beispiel ein Textfeld) zum selben Panel hinzufügt. Die Absicht ist, so viele Steuerelemente hinzuzufügen, wie der LinkButton geklickt wurde (d. H. Ich klicke einmal darauf, ein Feld, dann ein weiterer Klick gibt mir 2 Felder, ein weiterer Klick fügt ein drittes hinzu). In dem folgenden Code verwende ich das aktuelle Datum und die Uhrzeit serialisiert, um eine eindeutige ID für jedes Textfeldsteuerelement zu erstellen.ASP.NET dynamisch erstellte Steuerelemente und Postback

Wenn ich den Code ausführen, wird durch Klicken auf "Filter hinzufügen" ein neues Textfeld erstellt, aber nach dem erneuten Klicken wird ein neues erstellt und das vorherige gelöscht. Stattdessen möchte ich die vorherige Textbox sowie alle darin enthaltenen Daten beibehalten.

Ihre Hilfe wird geschätzt.

Im aspx:

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

</asp:Panel> 

In den 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); 
} 

Antwort

16

Für alle anderen, die versuchen, so etwas zu tun: nicht. Denken Sie stattdessen an den Informationsfluss und verstehen Sie, dass es einen besseren Weg gibt, dies zu tun. Die Eingabesteuerung (en) müssen nicht dynamisch erstellt werden. Sie können statisch sein, und nach dem Ausfüllen und Senden auf einem muss diese Information irgendwohin gehen (z. B. Datenbank, Cache, Sitzung). Sobald es dort ist, durchlaufen Sie beim Postback alle Elemente in Ihrem Speicher Ihrer Wahl und erstellen eine Anzeige für sie.

Das habe ich gemacht und es hat das Leben viel einfacher gemacht. Hoffe es hilft jemandem.

+0

Was würden Sie in einer Situation tun, in der Fragebögen (Umfragen) in einer bestimmten Anwendung erstellt und über einen Webservice präsentiert werden die Website holt eine Umfrage und rendert die Felder dafür? in diesem Fall ist die dynamische Erstellung von Inhalten die einzige geeignete Option nein? – Sander

+0

Ja, das dynamische Erstellen des Inhalts ist in Ordnung, aber es muss nicht inkrementell sein, wie ich es versucht habe; Ich nehme an, dass Ihr Web-Service jedes Mal alle Ergebnisse zurückgibt. In diesem Fall haben Sie jedes Mal alle Ergebnisse gelöscht. Bei Verwendung von Viewstate und Caching sollte Ihre Leistung ziemlich gut sein. –

+1

Du bist ein Genie. Ich habe versucht, dasselbe wie das OP zu erreichen, aber dies hat mir klar gemacht, dass ich statt mehrerer Steuerinstanzen nur das neue Steuerelement in einem modalen Fenster anzeigen und in ihrem modalen "Speichern" speichern und in den Datenspeicher übernehmen kann dann laden Sie das auf die Seite sehr leicht. Tausend Dankeschöns. Ich habe 3 Tage und den ganzen heutigen Abend damit verbracht, dieses herauszufinden. –

0

Versuchen Hinzufügen

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

Ich wickelte alles in Page_Init in der! IsPostBack wenn. Dadurch wurden die Linkbuttons und der Anfangszustand der Seite geladen, aber wenn ich auf einen dieser Linkbuttons klicke, verschwinden alle und nichts ist auf der Seite. –

1

Ich glaube, dass Sie auf jede Steuer neu erstellen müssen werden jeder Postback.

Ich weiß, dass das Repeater-Steuerelement genügend Informationen über seine Kinder speichert, um sie neu zu erstellen, wenn sie datengebunden sind ... Sie können es möglicherweise verwenden, um ein wenig Arbeit zu sparen.

+0

Sie müssen sie bei jedem Postback neu erstellen. Irgendwo müssen Sie speichern, wie viele Sie bereits haben. Vielleicht im Viewstate oder so. – Remy

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

Das wird nicht funktionieren - es ist ein Lebenszyklusproblem, wie Sie in Ihrer Frage abgeleitet haben. Es gibt viele Möglichkeiten, wie Sie damit arbeiten können, aber Honus Wagners Vorschlag ist der flexibelste.

Was passiert hier ist, dass Sie Controls.Add im Event-Handler aufrufen und das Steuerelement wird der Kontrollliste hinzugefügt, und bei der nächsten Anfrage (sei es eine teilweise Postback, volle Postback oder neue Seite getroffen), diese Kontrolle ist weg, weil du sie nirgendwo mehr beibehalten hast.

Hier ist, was gerade jetzt in Ihre Seite ein Event-Lebenszyklus passiert:

  1. Seite ruft OnInit und fügt Ihre Linkbutton
  2. Der Benutzer klickt auf die Linkbutton
  3. Seite OnInit ruft die Postbacks Anfrage zu beginnen.Die Linkbutton ist
  4. Die Event-Handler neu erstellt wird aufgerufen, die Ihr TextBox dynamisch erstellt und fügt sich die Steuer Sammlung
  5. Der Benutzer kann die Linkbutton klickt wieder
  6. Seite ruft OnInit die Linkbutton wieder hinzuzufügen. Die pnlFilter.Controls-Auflistung ist zu diesem Zeitpunkt leer, mit Ausnahme von Elementen, die Sie in Ihrem Markup statisch deklariert haben.
  7. Event-Handler wird aufgerufen und der Kontrollliste wird ein neuer TextBox hinzugefügt.

Ich bin nicht sicher, dass es die beste Praxis ist, aber ich habe Erfolg mit einem Modell ähnlich wie diese hatte (beachten Sie, dass ich diesen Code nicht getestet haben - es kann angepasst werden müssen):

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); 
} 

Beachten Sie, dass ich bin nicht sicher über Hinzufügen von tatsächlichen Control-Objekte zum Sitzungsspeicher - ich glaube, es gibt Probleme mit den Steuerelement-IDs, die Fehler beim Postback verursachen (vielleicht ist ein Steuerelement nicht serialisierbar?). In der von mir entwickelten Lösung habe ich eine neue TextBox/Label/ComboBox/etc in meiner Entsprechung der GenerateControl-Methode generiert und eine benutzerdefinierte Containerklasse in der PersistedControls-Sammlung gespeichert, die die verschiedenen Eigenschaften des UI-Steuerelements enthielt, das ich generieren müsste es auf jeder Seite Init.

Verwandte Themen