2010-11-18 18 views
15

Wiem, że to pytanie zostało zadane tysiące razy, i już wcześniej z nim walczyłem, ale z jakiegoś powodu nie mogę osiągnąć tego, co chcę osiągnąć ... mieć dynamicznie dodawany LinkButton, który po kliknięciu będzie dynamicznie dodawał kontrolkę (w tym przykładzie pole tekstowe) do tego samego panelu. Celem jest ciągłe dodawanie tylu kontrolek, ile razy kliknięto LinkButton (tj. Kliknę raz, jedno pole, kolejne kliknięcie da mi 2 pola, kolejne kliknięcie doda 3). W poniższym kodzie używam bieżącej daty i czasu zserializowanych w celu utworzenia niepowtarzalnego identyfikatora dla każdego formantu pola tekstowego.ASP.NET dynamicznie utworzone sterowanie i odświeżenie

Po uruchomieniu kodu kliknięcie "Dodaj filtr" spowoduje wygenerowanie nowego pola tekstowego, ale po ponownym kliknięciu spowoduje utworzenie nowego, a następnie pozbędzie się go. Zamiast tego chcę uporać się z poprzednim polem tekstowym oraz wszelkimi danymi przesłanymi w nim.

Twoja pomoc jest doceniana.

W aspx:

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

</asp:Panel> 

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

Odpowiedz

16

Dla każdego, kto próbuje zrobić coś takiego: nie rób tego. Zamiast tego pomyśl o przepływie informacji i zrozum, że jest lepszy sposób na zrobienie tego. Formanty wejściowe nie muszą być tworzone dynamicznie. Mogą być statyczne, a po wypełnieniu i przesłaniu jednego, informacja musi gdzieś iść (baza danych, pamięć podręczna, sesja, na przykład). Gdy już się tam znajdzie, na poczcie zwrotnej przejrzyj wszystkie pozycje w wybranym miejscu i utwórz dla nich ekran.

To właśnie zrobiłem i to znacznie ułatwiło życie. Mam nadzieję, że to komuś pomaga.

+0

Co zrobiłbyś w sytuacji, gdy kwestionariusze (ankiety) są tworzone w określonej aplikacji, a prezentowane za pośrednictwem usługi internetowej witryna pobiera ankietę i wyświetla dla niej pola? w takim przypadku dynamicznie tworzenie treści jest jedyną odpowiednią opcją nie? – Sander

+0

Tak, dynamiczne tworzenie zawartości jest w porządku, ale nie musi być przyrostowe, tak jak próbowałem to zrobić; Zakładam, że twoja usługa sieciowa zwraca wszystkie wyniki za każdym razem, w takim przypadku za każdym razem renderujesz je wszystkie. Przy użyciu stanu wyświetlania i buforowania wydajność powinna być całkiem dobra. –

+1

Jesteś geniuszem. Próbowałem osiągnąć to samo co OP, ale to uświadomiło mi, że mogę zamiast dodawać wiele instancji sterowania, mogę po prostu pokazać nową kontrolkę w oknie modalnym i "zapisać" w jej modalu, zatwierdzić do magazynu danych i następnie bardzo łatwo załaduj to na stronę. Tysiące dziękuję. Spędziłem 3 dni i całą noc próbując to wymyślić. –

0

warto dodać,

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

Zawinęłam wszystko wewnątrz Page_Init w! IsPostBack, jeśli. Robiąc to załadowałem linki i początkowy stan strony, ale kiedy kliknę na jeden z tych linków, wszystkie znikają i nic nie jest na stronie. –

1

Uważam, że trzeba odtworzyć każdą kontrolę na każda informacja zwrotna.

Wiem, że kontrolka Repeater przechowuje wystarczającą ilość informacji na temat swoich dzieci, aby odtworzyć je, gdy baza danych ... Możesz być w stanie go użyć, aby zaoszczędzić trochę pracy.

+0

Musisz utworzyć je ponownie przy każdym odświeżeniu strony. Gdzieś musisz przechowywać ile masz. Może w Viewstate czy coś takiego. – Remy

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

To nie zadziała - jest to kwestia cyklu życia, o której pisałeś w swoim pytaniu. Istnieje wiele sposobów, w jakie można z tym pracować, ale sugestia Honusa Wagnera jest najbardziej elastyczna.

To co się dzieje, to to, że dzwonisz do Controls.Add w module obsługi zdarzenia, a kontrola jest dodawana do listy kontrolnej, a na następnym żądanie (częściowy odświeżenie, pełny odświeżenie lub nowa strona), ta kontrola zniknęła, ponieważ nie przetrwałeś jej nigdzie.

Oto, co się dzieje w twojej stronie wydarzenia cyklu teraz:

  1. Strona nazywa OnInit i dodaje swoją LinkButton
  2. użytkownik kliknie LinkButton
  3. Strona nazywa OnInit zacząć wniosek ogłaszania zwrotnego.LinkButton jest odtwarzany
  4. obsługi zdarzeń jest wywoływana, który dynamicznie tworzy swój TextBox i dodaje go do kolekcji kontroli
  5. użytkownik kliknie LinkButton ponownie
  6. Strona nazywa OnInit ponownie dodać LinkButton. Kolekcja pnlFilter.Controls jest w tym momencie pusta, z wyjątkiem wszystkich elementów, które zadeklarowałeś statycznie w swoim znaczniku.
  7. Program obsługi zdarzeń jest wywoływany, a do listy sterowania dodawany jest nowy element TextBox.

nie jestem pewien, że jest to najlepsza praktyka, ale miałem sukces modelu podobnego do tego (należy pamiętać, że nie testowałem ten kod - może wymagać korekty):

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

Zauważ, że nie jestem pewien o dodawaniu rzeczywistych obiektów kontrolnych do magazynu sesji - wydaje mi się, że są problemy z identyfikatorami kontrolnymi, które spowodują błędy w poczcie zwrotnej (być może kontrola nie jest możliwa do serializacji?). W opracowanym przeze mnie rozwiązaniu wygenerowałem nowy TextBox/Label/ComboBox/etc w moim odpowiedniku metody GenerateControl i zachowałem niestandardową klasę kontenera w kolekcji PersistedControls, która zawierała różne właściwości kontrolki interfejsu użytkownika, którą musiałbym wygenerować to na każdej stronie Init.

Powiązane problemy