Problem:
In Web Anwendung kann es notwendig sein ListBound Controls einer Seite dynamisch nach einem vorher gespeicherten Muster wieder aufzubauen. Solange sich der Benutzer auf einer Seite bewegt speichert ASP.NET solche Informationen im Viewstate ab, sobald man allerdings zwischen verschiedenen Seiten navigiert ist auch diese Information verloren. (Anmerkung: Wenn mit
Server.Transfer(string path, bool preserveForm);
auf dem Server navigiert wird kann der Formstatus, also auch der Viewstate an die nächste Seite übergeben werden, preserveForm=true. In diesem Artikel sollen allerdings die Möglichkeiten der seitenübergreifenden Statusverwaltung benutzt werden).
Beispiel:
Das Beispiel an dem dieser Artikel sich orientiert ist eine Datanbank mit 3 Tabellen, die folgendermaßen aufgebaut sind:
Genres:
Spaltenname |
Typ |
Beschreibung |
GenreId |
int, Primary, NotNull |
Key für das Genre |
GenreName |
nvarchar(50) |
Name des Genres |
Series:
Spaltenname |
Typ |
Beschreibung |
SeriesId |
int, Primary, NotNull |
Key für die Serie |
SeriesName |
nvarchar(50) |
Name der Serie |
GenreId |
int, NotNull |
Fremdschlüssel aus Genres |
Characters:
Spaltenname |
Typ |
Beschreibung |
CharacterId |
int, Primary, NotNull |
Key für den Rollencharakter |
CharacterName |
nvarchar(50) |
Name des Rollencharakters |
DubberName |
nvarchar(50) |
Name des deutschen Synchronsprechers |
SeriesId |
int, NotNull |
Fremdschlüssel aus Series |
Szenario:
Der Benutzer einer Webanwendung wählt aus zwei ListBound Controls (Dropdown-Listen) Filter aus, auf die sich eine darunter liegende GridView (grdvwCharactersTable) bezieht. Dabei regelt die erste DropDown-List (ddlstGenres) den Inhalt der zweiten DropDown-List (ddlstSeries). Jede Dropdown-List ist dafür mit einer eigenen SqlDataSource (sqldtsrcDdlstGenres um ddlstGenres mit den Werten aus Genres zu befüllen, respektive sqldtsrcDdlstSeries um ddlstSeries mit den Werten aus Series zu befüllen) verbunden. Die Datenquelle sqldtsrcDdlstSeries verwendet als Where Paramter den momentan gesetzten Wert von ddlstGenre um nur Serien eines bestimmten Genres anzuzeigen. Ebenso ist die Where Bedinung der Datenquelle der Gridview (grdvwCharactersTable) an das Control ddlstSeries geknüpft.
Wenn der Benutzer nun Werte in den DropDown Listen ändert, die Seite verlässt und wieder zurückkehrt sind alle DropDown-Listen und die GridView wieder in ihrem Ursprungszustand. Dieser Effekt soll umgangen werden, der Status seit dem Verlassen der Seite muss wieder hergestellt sein.
Lösung:
Beim Verlassen der Seite muss darauf geachtet werden, die Statusinformationen (Werte der Dropdown-Listen) für den aktuellen Benutzer zu speichern. Hierzu bittet sich das ASP.NET Session Objekt an. Im Click Event des LinkButtons, der die Seite verlässt, wird dazu erst ein Dictionary Objekt erzeugt, das die aktuellen Werte beider DropDown-Listen enthält und das dann zur Session gespeichert werden kann.
protected void LinkButton1_Click(object sender, EventArgs e)
{
Dictionary<string, string> dictState = new Dictionary<string, string>
{
{"GenreId", ddlstGenres.SelectedValue},
{"SeriesId", ddlstSeries.SelectedValue}
};
Session["State"] = dictState;
Response.Redirect(@"~\Default2.aspx");
}
Beim wiederholten Laden der Seite muss also erst geprüft werden ob die Session vorhanden ist. Ist das der Fall kann das Dictionary wieder neu aufgebaut werden. Nun ist es wichtig die Reihenfolge beim Wiederherstellen des Statuses zu beachten:
protected void Page_Load(object sender, EventArgs e)
{
if (Session["State"] != null)
{
Dictionary<string, string> dictState = (Dictionary<string, string>)Session["State"];
ddlstGenres.DataBind();
ddlstGenres.Items.FindByValue(dictState["GenreId"]).Selected = true;
ddlstSeries.DataBind();
ddlstSeries.Items.FindByValue(dictState["SeriesId"]).Selected = true;
Session["State"] = null;
}
}
- Zuerst muss die ddlstGenres ein DataBind ausführen, damit die ListItem Collection bekannt wird, die für dieses Control gilt.
- Das entsprechende ListItem muss als Selected gekennzeichnet werden. Dazu kann der Funktion FindByValue() der Wert aus dem Dictionary übergeben werden.
- Nachdem nun in der ersten DropDown-List der Wert wieder hergestellt wurde kann das DataBind an ddlstSeries ausgeführt werden (das sich ja auf diesen ersten Wert bezieht).
- Nun muss auch hier das ListItem gefunden werden das zuvor angewählt war um ihm dann den Selected=true Status zu verpassen.
- Die Session wird dann nicht mehr benötigt und muss auf null gesetzt werden (Der Viewstate kümmert sich ab sofort wieder um Änderungen, die auf der Seite statt finden)
- Anmerkung: Auch das GridView muss an dieser Stelle kein DataBind ausführen, das passiert automatisch im Page_PreRender Event des Page Life Cycles (Schaden wird es allerdings auch nicht).
Zur Verdeutlichung wann welche DataBind Funktionen aufgerufen werden wurden im Beipsiel Programm die entsprechenden DataBind und DataBound Events abgefangen und im Trace Output sichtbar gemacht.
Außerdem gibt es einen Bugfix, der in der Methode ddlstGenres_SelectedIndexChanged behandelt wird. Wenn sich das Genre ändert (bei Zugriff auf die gleiche Seite) muss auch die Series DropDown-List neu gebunden werden (damit aktualisiert sich dann auch das GridView):
protected void ddlstGenres_SelectedIndexChanged(object sender, EventArgs e)
{
ddlstSeries.DataBind();
}
Der Source Code zum Artikel kann hier runter geladen werden:
Demo zum Artikel