Opiszę sprawę jeszcze raz, stworzyłem nowy przykład aby był maksymalnie prosty, jednocześnie aby dobrze ilustrował mój problem.
Na stronie mamy pierwotnie trzy kontrolki: Panel, Label i Button. Do kontrolki Panel jest wrzucana kontrolka TextBox dynamicznie utworzona podczas zdarzenia Page_Load. Po kliknięciu na Button za pomocą metody FindControl jest odczytywana wartość wprowadzona do TextBoxa, i przypisywana do właściwości Text kontrolki Label. Działa jak należy ! Problem pojawia się w drugim przykładzie:/
Plik Default.aspx :
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="generowanie_html_5._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 runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Panel ID="Panel1" runat="server">
</asp:Panel>
<br />
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<br />
<asp:Button ID="odczytajWartosc" runat="server" Text="Odczytaj wartosci z kontrolek" onclick="odczytajWartosc_Click" />
</div>
</form>
</body>
</html>
Plik Default.aspx.cs :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace generowanie_html_5
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
TextBox txt = new TextBox();
txt.ID = "textBox";
this.Panel1.Controls.Add(txt);
}
protected void odczytajWartosc_Click(object sender, EventArgs e)
{
TextBox txt = new TextBox();
txt = (TextBox)this.FindControl("textBox");
Label1.Text = txt.Text;
}
}
}
Problem jest kiedy w podobny sposób próbuję odczytać kontrolkę dynamicznie utworzoną po kliknięciu przycisku.
Plik Default.aspx :
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="generowanie_html_5._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 runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Panel ID="Panel1" runat="server">
</asp:Panel>
<br />
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<br />
<asp:Button ID="dodajKontrolke" runat="server" Text="Dodaj kontrolke" onclick="dodajKontrolke_Click" />
<br />
<asp:Button ID="odczytajWartosc" runat="server" Text="Odczytaj wartosci z kontrolek" onclick="odczytajWartosc_Click" />
</div>
</form>
</body>
</html>
Plik Default.aspx.cs :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace generowanie_html_5
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
TextBox txt = new TextBox();
txt.ID = "textBox";
this.Panel1.Controls.Add(txt);
}
protected void dodajKontrolke_Click(object sender, EventArgs e)
{
TextBox txt = new TextBox();
txt.ID = "textBox2";
this.Panel1.Controls.Add(txt);
}
protected void odczytajWartosc_Click(object sender, EventArgs e)
{
TextBox txt = new TextBox();
txt = (TextBox)this.FindControl("textBox");
Label1.Text = txt.Text;
TextBox txt2 = new TextBox();
txt2 = (TextBox)this.FindControl("textBox2");
Label1.Text = txt2.Text;
}
}
}
Początek kodu jest identyczny jak w poprzednim przykładzie. Dodany jest Button, który po kliknięciu dodaje do kontrolki Panel jeszcze jeden TextBox. Kliknięcie przycisku "Odczytaj wartości z kontrolek" tym razem wyrzuca błąd, a dokładnie debugger zatrzymuje się na :
Label1.Text = txt2.Text;
wskazując że obiekt txt2 jest null - czyli jak rozumiem nie został znaleziony na stronie. Dla jasności wklejam jeszcze źródło wygenerowanej strony:
<!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><title>
</title></head>
<body>
<form name="form1" method="post" action="Default.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTM1ODgwNzc1MWRkkxiP1nScQD/61zrWMMsGLf/427k=" />
</div>
<div>
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWBQKvw9HfBALMyt74CwLMyvbZDALTq4smAp/Yl70H37AlxIIC/7GPfV5r9N0tjZWGZFY=" />
</div>
<div>
<div id="Panel1">
<input name="textBox" type="text" id="textBox" /><input name="textBox2" type="text" id="textBox2" />
</div>
<br />
<span id="Label1">Label</span>
<br />
<input type="submit" name="dodajKontrolke" value="Dodaj kontrolke" id="dodajKontrolke" />
<br />
<input type="submit" name="odczytajWartosc" value="Odczytaj wartosci z kontrolek" id="odczytajWartosc" />
</div>
</form>
</body>
</html>
Zachęcam do odpalenia tego kodu u siebie, próbowałem na różne sposoby, między innymi tworząc kilka stron *.aspx, przekazując formularz do kolejnej strony i odwołując się nie przez this tylko przez PreviousPage, zawsze błąd pojawiał się w tym samym momencie. Ostatecznie opisana metoda ma być wykorzystana do generowania formularza w następujący sposób: Pierwsza strona lista z nazwami Formularzy do wyboru, po kliknięciu na podstawie wybranej nazwy jest pobierany z bazy szablon formularza i jest dla niego generowany formularz na stronie (do tego etapu jest ok), następnie wartości po wypełnieniu formularza mają być zczytane i wprowadzone do bazy po kliknięciu kolejnego przycisku, tutaj właśnie pojawia się opisany wyżej błąd bo przykład jest analogiczny. Nie znajduję kontrolek TextBox na stronie mimo że w źródle strony widzę że są. Co ciekawe jeśli kontrolka jest utworzona statycznie bezpośrednio w Default.aspx lub podczas pierwszego uruchomienia w Page_Load to jest zczytywana przez FindControl prawidłowo na każdym etapie.