Geschachtelte Datenwebsteuerelemente (C#)
von Scott Mitchell
In diesem Tutorial erfahren Sie, wie Sie einen Repeater verwenden, der in einem anderen Repeater geschachtelt ist. Die Beispiele veranschaulichen, wie sie den inneren Repeater sowohl deklarativ als auch programmgesteuert auffüllen.
Einführung
Neben statischer HTML- und Datenbindungssyntax können Vorlagen auch Websteuerelemente und Benutzersteuerelemente enthalten. Diese Websteuerelemente können ihre Eigenschaften über deklarative, Datenbindungssyntax zugewiesen haben oder programmgesteuert in den entsprechenden serverseitigen Ereignishandlern zugegriffen werden.
Durch das Einbetten von Steuerelementen in eine Vorlage können die Darstellung und die Benutzeroberfläche angepasst und verbessert werden. Im Tutorial Verwenden von TemplateFields im GridView-Steuerelement haben wir beispielsweise gezeigt, wie Sie die Anzeige von GridView anpassen, indem Sie ein Calendar-Steuerelement in einem TemplateField hinzufügen, um das Einstellungsdatum eines Mitarbeiters anzuzeigen. In den Tutorials Zum Hinzufügen von Validierungssteuerelementen zu den Bearbeitungs- und Einfügeschnittstellen und zum Anpassen der Datenänderungsschnittstelle haben wir erfahren, wie Sie die Bearbeitungs- und Einfügeschnittstellen anpassen, indem Sie Validierungssteuerelemente, TextBoxes, DropDownLists und andere Websteuerelemente hinzufügen.
Vorlagen können auch andere Datenwebsteuerelemente enthalten. Das heißt, wir können eine DataList haben, die eine andere DataList (oder Repeater, GridView oder DetailsView usw.) in ihren Vorlagen enthält. Die Herausforderung bei einer solchen Schnittstelle besteht darin, die entsprechenden Daten an das interne Daten-Websteuerelement zu binden. Es gibt verschiedene Ansätze, die von deklarativen Optionen mit objectDataSource bis hin zu programmgesteuerten Optionen reichen.
In diesem Tutorial erfahren Sie, wie Sie einen Repeater verwenden, der in einem anderen Repeater geschachtelt ist. Der äußere Repeater enthält ein Element für jede Kategorie in der Datenbank, das den Namen und die Beschreibung der Kategorie anzeigt. Der innere Repeater jedes Kategorieelements zeigt Informationen zu jedem Produkt, das zu dieser Kategorie gehört (siehe Abbildung 1) in einer Aufzählungsliste an. In unseren Beispielen wird veranschaulicht, wie der innere Repeater sowohl deklarativ als auch programmgesteuert aufgefüllt wird.
Abbildung 1: Jede Kategorie wird zusammen mit ihren Produkten aufgelistet (Klicken Sie hier, um das bild in voller Größe anzuzeigen)
Schritt 1: Erstellen des Kategorieeintrags
Beim Erstellen einer Seite, die geschachtelte Daten-Websteuerelemente verwendet, finde ich es hilfreich, zuerst das äußerste Daten-Websteuerelement zu entwerfen, zu erstellen und zu testen, ohne sich um das innere geschachtelte Steuerelement kümmern zu müssen. Führen Sie daher zunächst die Schritte durch, die zum Hinzufügen eines Repeaters zur Seite erforderlich sind, auf der der Name und die Beschreibung für jede Kategorie aufgeführt sind.
Öffnen Sie zunächst die NestedControls.aspx
Seite im DataListRepeaterBasics
Ordner, fügen Sie der Seite ein Repeater-Steuerelement hinzu, und legen Sie dessen ID
Eigenschaft auf fest CategoryList
. Wählen Sie im Smarttag des Repeaters aus, um eine neue ObjectDataSource mit dem Namen CategoriesDataSource
zu erstellen.
Abbildung 2: Benennen Sie die neue ObjectDataSource CategoriesDataSource
(Klicken Sie hier, um das bild in voller Größe anzuzeigen)
Konfigurieren Sie die ObjectDataSource so, dass sie ihre Daten aus der Methode der CategoriesBLL
Klasse s GetCategories
abruft.
Abbildung 3: Konfigurieren der ObjectDataSource für die Verwendung der Methode der CategoriesBLL
GetCategories
Klasse (Klicken Sie hier, um das bild in voller Größe anzuzeigen)
Um den Vorlageninhalt des Repeaters anzugeben, müssen Wir zur Quellansicht wechseln und die deklarative Syntax manuell eingeben. Fügen Sie ein ItemTemplate
hinzu, das den Namen der Kategorie in einem <h4>
Element und die Beschreibung der Kategorie in einem Absatzelement (<p>
) anzeigt. Außerdem trennen wir jede Kategorie durch eine horizontale Regel (<hr>
). Nachdem Sie diese Änderungen vorgenommen haben, sollte Ihre Seite eine deklarative Syntax für den Repeater und ObjectDataSource enthalten, die der folgenden ähnelt:
<asp:Repeater ID="CategoryList" DataSourceID="CategoriesDataSource"
EnableViewState="False" runat="server">
<ItemTemplate>
<h4><%# Eval("CategoryName") %></h4>
<p><%# Eval("Description") %></p>
</ItemTemplate>
<SeparatorTemplate>
<hr />
</SeparatorTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
Abbildung 4 zeigt unseren Fortschritt, wenn wir über einen Browser angezeigt werden.
Abbildung 4: Name und Beschreibung jeder Kategorie sind aufgelistet, getrennt durch eine horizontale Regel (Klicken Sie, um das bild in voller Größe anzuzeigen)
Schritt 2: Hinzufügen des geschachtelten Product Repeaters
Wenn die Kategorieliste abgeschlossen ist, besteht unsere nächste Aufgabe darin, einen Repeater zu den s ItemTemplate
hinzuzufügen, der CategoryList
Informationen zu den Produkten anzeigt, die zur entsprechenden Kategorie gehören. Es gibt eine Reihe von Möglichkeiten, die Daten für diesen inneren Repeater abzurufen, von denen wir in Kürze zwei untersuchen werden. Zunächst erstellen wir einfach den Produkt-Repeater innerhalb des CategoryList
Repeaters ItemTemplate
. Insbesondere lassen Sie den Produktwiederholungsgeber jedes Produkt in einer Aufzählungsliste mit jedem Listenelement anzeigen, das den Namen und den Preis des Produkts enthält.
Um diesen Repeater zu erstellen, müssen Sie die deklarative Syntax und die Vorlagen des inneren Repeaters manuell in die CategoryList
s ItemTemplate
eingeben. Fügen Sie das folgende Markup innerhalb der CategoryList
Repeater-S hinzu ItemTemplate
:
<asp:Repeater ID="ProductsByCategoryList" EnableViewState="False"
runat="server">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><strong><%# Eval("ProductName") %></strong>
(<%# Eval("UnitPrice", "{0:C}") %>)</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
Schritt 3: Binden der Category-Specific Produkte an den ProductsByCategoryList Repeater
Wenn Sie die Seite an diesem Punkt über einen Browser aufrufen, sieht Ihr Bildschirm wie in Abbildung 4 aus, da wir noch keine Daten an den Repeater binden müssen. Es gibt einige Möglichkeiten, wie wir die entsprechenden Produktdatensätze abrufen und an den Repeater binden können, einige effizienter als andere. Die Standard Herausforderung besteht hier darin, die entsprechenden Produkte für die angegebene Kategorie zurück zu erhalten.
Auf die Daten, die an das innere Repeater-Steuerelement gebunden werden sollen, kann entweder deklarativ über eine ObjectDataSource in der CategoryList
Repeater-Datei ItemTemplate
oder programmgesteuert über die CodeBehind-Seite der ASP.NET Seite zugegriffen werden. Auf ähnliche Weise können diese Daten entweder deklarativ an den inneren Repeater gebunden werden – über die innere Repeater-Eigenschaft oder über deklarative Datenbindungssyntax DataSourceID
oder programmgesteuert durch Verweisen auf den inneren Repeater im Ereignishandler des CategoryList
Repeaters ItemDataBound
, programmgesteuertes Festlegen der DataSource
Eigenschaft und Aufrufen der - DataBind()
Methode. Lassen Sie uns jeden dieser Ansätze untersuchen.
Deklarativer Zugriff auf die Daten mit einem ObjectDataSource-Steuerelement und demItemDataBound
Ereignishandler
Da wir die ObjectDataSource in dieser Tutorialreihe ausführlich verwendet haben, besteht die natürlichste Wahl für den Zugriff auf Daten für dieses Beispiel darin, bei der ObjectDataSource zu bleiben. Die ProductsBLL
-Klasse verfügt über eine GetProductsByCategoryID(categoryID)
-Methode, die Informationen zu den Produkten zurückgibt, die zu dem angegebenen categoryID
gehören. Aus diesem Grund können wir dem CategoryList
Repeater eine ItemTemplate
ObjectDataSource hinzufügen und konfigurieren, um auf die Daten dieser Klasse s-Methode zuzugreifen.
Leider lässt der Repeater das Bearbeiten seiner Vorlagen über die Entwurfsansicht nicht zu, sodass wir die deklarative Syntax für dieses ObjectDataSource-Steuerelement manuell hinzufügen müssen. Die folgende Syntax zeigt die CategoryList
Repeater s ItemTemplate
nach dem Hinzufügen dieses neuen ObjectDataSource (ProductsByCategoryDataSource
):
<h4><%# Eval("CategoryName") %></h4>
<p><%# Eval("Description") %></p>
<asp:Repeater ID="ProductsByCategoryList" EnableViewState="False"
DataSourceID="ProductsByCategoryDataSource" runat="server">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><strong><%# Eval("ProductName") %></strong> -
sold as <%# Eval("QuantityPerUnit") %> at
<%# Eval("UnitPrice", "{0:C}") %></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="ProductsByCategoryDataSource" runat="server"
SelectMethod="GetProductsByCategoryID" TypeName="ProductsBLL">
<SelectParameters>
<asp:Parameter Name="CategoryID" Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>
Wenn Sie den ObjectDataSource-Ansatz verwenden, müssen Sie die ProductsByCategoryList
Repeater-Eigenschaft DataSourceID
auf die ID
der ObjectDataSource (ProductsByCategoryDataSource
) festlegen. Beachten Sie außerdem, dass unsere ObjectDataSource über ein <asp:Parameter>
-Element verfügt, das den categoryID
Wert angibt, der an die GetProductsByCategoryID(categoryID)
-Methode übergeben wird. Aber wie geben wir diesen Wert an? Im Idealfall können wir einfach die DefaultValue
Eigenschaft des Elements mithilfe der <asp:Parameter>
Datenbindungssyntax wie folgt festlegen:
<asp:Parameter Name="CategoryID" Type="Int32"
DefaultValue='<%# Eval("CategoryID")' />
Leider ist die Syntax der Datenbindung nur in Steuerelementen gültig, die über ein DataBinding
Ereignis verfügen. Der Parameter
Klasse fehlt ein solches Ereignis, weshalb die obige Syntax ungültig ist und zu einem Laufzeitfehler führt.
Um diesen Wert festzulegen, müssen wir einen Ereignishandler für das CategoryList
Repeater-Ereignis ItemDataBound
erstellen. Denken Sie daran, dass das ItemDataBound
Ereignis einmal für jedes Element ausgelöst wird, das an den Repeater gebunden ist. Daher können wir jedes Mal, wenn dieses Ereignis für den äußeren Repeater ausgelöst wird, dem Parameter ObjectDataSource CategoryID
den ProductsByCategoryDataSource
aktuellen CategoryID
Wert zuweisen.
Erstellen Sie mit dem folgenden Code einen Ereignishandler für das CategoryList
Repeater-Ereignis ItemDataBound
:
protected void CategoryList_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem ||
e.Item.ItemType == ListItemType.Item)
{
// Reference the CategoriesRow object being bound to this RepeaterItem
Northwind.CategoriesRow category =
(Northwind.CategoriesRow)((System.Data.DataRowView)e.Item.DataItem).Row;
// Reference the ProductsByCategoryDataSource ObjectDataSource
ObjectDataSource ProductsByCategoryDataSource =
(ObjectDataSource)e.Item.FindControl("ProductsByCategoryDataSource");
// Set the CategoryID Parameter value
ProductsByCategoryDataSource.SelectParameters["CategoryID"].DefaultValue =
category.CategoryID.ToString();
}
}
Dieser Ereignishandler stellt zunächst sicher, dass es sich um ein Datenelement anstelle des Kopf-, Fußzeilen- oder Trennelements handelt. Als Nächstes verweisen wir auf den tatsächlichen CategoriesRow
instance, der gerade an den aktuellen RepeaterItem
gebunden wurde. Schließlich verweisen wir auf die ObjectDataSource im ItemTemplate
und weisen ihren CategoryID
Parameterwert dem CategoryID
des aktuellen RepeaterItem
zu.
Bei diesem Ereignishandler ist der ProductsByCategoryList
Repeater in jedem RepeaterItem
an diese Produkte in der RepeaterItem
Kategorie s gebunden. Abbildung 5 zeigt einen Screenshot der resultierenden Ausgabe.
Abbildung 5: Der äußere Repeater Listen jede Kategorie; die innere Listen die Produkte für diese Kategorie (Klicken Sie, um das bild in voller Größe anzuzeigen)
Programmgesteuerter Zugriff auf die Produkte nach Kategoriedaten
Anstatt eine ObjectDataSource zum Abrufen der Produkte für die aktuelle Kategorie zu verwenden, könnten wir eine Methode in der CodeBehind-Klasse der ASP.NET Seite (oder im App_Code
Ordner oder in einem separaten Klassenbibliotheksprojekt) erstellen, die den entsprechenden Satz von Produkten zurückgibt, wenn sie in einem CategoryID
übergeben werden. Stellen Sie sich vor, wir hätten eine solche Methode in der CodeBehind-Klasse der ASP.NET Seite und hätten den Namen GetProductsInCategory(categoryID)
. Mit dieser Methode könnten wir die Produkte für die aktuelle Kategorie mithilfe der folgenden deklarativen Syntax an den inneren Repeater binden:
<asp:Repeater runat="server" ID="ProductsByCategoryList" EnableViewState="False"
DataSource='<%# GetProductsInCategory((int)(Eval("CategoryID"))) %>'>
...
</asp:Repeater>
Die Repeater-Eigenschaft verwendet die Datenbindungssyntax DataSource
, um anzugeben, dass die Daten von der GetProductsInCategory(categoryID)
-Methode stammen. Da Eval("CategoryID")
ein Wert vom Typ Object
zurückgegeben wird, wird das Objekt in ein Integer
umgewandelt, bevor es an die GetProductsInCategory(categoryID)
-Methode übergeben wird. Beachten Sie, dass hier CategoryID
über die Datenbindungssyntax der im äußeren Repeater () zugegriffen wird,CategoryList
der an die Datensätze in der Categories
Tabelle gebunden istCategoryID
. Daher wissen wir, dass es CategoryID
sich nicht um einen Datenbankwert NULL
handeln kann, weshalb wir die Eval
Methode blind umwandeln können, ohne zu überprüfen, ob es sich um einen DBNull
handelt.
Bei diesem Ansatz müssen wir die GetProductsInCategory(categoryID)
-Methode erstellen und den entsprechenden Satz von Produkten abrufen, wenn die bereitgestellten categoryID
. Dazu können Sie einfach die von der ProductsDataTable
ProductsBLL
Klasse s-Methode GetProductsByCategoryID(categoryID)
zurückgegebene zurückgeben. Erstellen Sie die GetProductsInCategory(categoryID)
-Methode in der CodeBehind-Klasse für unsere NestedControls.aspx
Seite. Verwenden Sie dazu den folgenden Code:
protected Northwind.ProductsDataTable GetProductsInCategory(int categoryID)
{
// Create an instance of the ProductsBLL class
ProductsBLL productAPI = new ProductsBLL();
// Return the products in the category
return productAPI.GetProductsByCategoryID(categoryID);
}
Diese Methode erstellt einfach eine instance der ProductsBLL
-Methode und gibt die Ergebnisse der GetProductsByCategoryID(categoryID)
Methode zurück. Beachten Sie, dass die Methode gekennzeichnet Public
sein muss oder Protected
; wenn die Methode markiert Private
ist, ist der Zugriff über das deklarative Markup der ASP.NET Seite nicht möglich.
Nachdem Sie diese Änderungen vorgenommen haben, um diese neue Technik zu verwenden, nehmen Sie sich einen Moment Zeit, um die Seite über einen Browser anzuzeigen. Die Ausgabe sollte mit der Ausgabe bei Verwendung des ObjectDataSource- und ItemDataBound
Ereignishandleransatzes identisch sein (siehe Abbildung 5, um einen Screenshot anzuzeigen).
Hinweis
Das Erstellen der Methode in der GetProductsInCategory(categoryID)
CodeBehind-Klasse der ASP.NET Seite kann wie ausgelastet erscheinen. Schließlich erstellt diese Methode einfach eine instance der ProductsBLL
-Klasse und gibt die Ergebnisse ihrer GetProductsByCategoryID(categoryID)
Methode zurück. Warum rufen Sie diese Methode nicht einfach direkt aus der Datenbindungssyntax im inneren Repeater auf, z. B.: DataSource='<%# ProductsBLL.GetProductsByCategoryID((int)(Eval("CategoryID"))) %>'
? Obwohl diese Syntax mit unserer aktuellen Implementierung der -Klasse nicht funktioniert (da es sich bei der ProductsBLL
GetProductsByCategoryID(categoryID)
Methode um eine instance-Methode handelt), können Sie ändernProductsBLL
, um eine statische Methode einzuschließenGetProductsByCategoryID(categoryID)
, oder die Klasse eine statische Instance()
Methode enthält, um eine neue instance der ProductsBLL
-Klasse zurückzugeben.
Während solche Änderungen die Notwendigkeit der GetProductsInCategory(categoryID)
Methode in der Code-Behind-Klasse der ASP.NET Seite überflüssig machen würden, bietet uns die Code-Behind-Klassenmethode mehr Flexibilität beim Arbeiten mit den abgerufenen Daten, wie wir in Kürze sehen werden.
Abrufen aller Produktinformationen auf einmal
Die beiden durchsichtigen Techniken, die wir untersucht haben, greifen diese Produkte für die aktuelle Kategorie auf, indem sie die Methode s GetProductsByCategoryID(categoryID)
der ProductsBLL
Klasse aufrufen (der erste Ansatz hat dies über eine ObjectDataSource, die zweite über die GetProductsInCategory(categoryID)
-Methode in der CodeBehind-Klasse). Jedes Mal, wenn diese Methode aufgerufen wird, ruft die Geschäftslogikebene die Datenzugriffsebene auf, die die Datenbank mit einer SQL-Anweisung abfragt, die Zeilen aus der Products
Tabelle zurückgibt, deren CategoryID
Feld mit dem angegebenen Eingabeparameter übereinstimmt.
Bei N-Kategorien im System werden bei diesem Ansatz N + 1-Aufrufe an die Datenbank eine Datenbankabfrage verwendet, um alle Kategorien abzurufen, und dann N Aufrufe, um die für jede Kategorie spezifischen Produkte abzurufen. Wir können jedoch alle benötigten Daten in nur zwei Datenbankaufrufen abrufen, um alle Kategorien abzurufen, und einen anderen, um alle Produkte abzurufen. Sobald wir alle Produkte haben, können wir diese Produkte filtern, sodass nur die Produkte, die dem aktuellen CategoryID
entsprechen, an den inneren Repeater dieser Kategorie gebunden sind.
Um diese Funktionalität bereitzustellen, müssen wir nur eine geringfügige Änderung an der -Methode in der GetProductsInCategory(categoryID)
CodeBehind-Klasse der ASP.NET Seite vornehmen. Anstatt die Ergebnisse der Methode der ProductsBLL
Klasse GetProductsByCategoryID(categoryID)
blind zurückzugeben, können wir stattdessen zuerst auf alle Produkte zugreifen (sofern noch nicht darauf zugegriffen wurde) und dann nur die gefilterte Ansicht der Produkte basierend auf der übergebenen CategoryID
zurückgeben.
private Northwind.ProductsDataTable allProducts = null;
protected Northwind.ProductsDataTable GetProductsInCategory(int categoryID)
{
// First, see if we've yet to have accessed all of the product information
if (allProducts == null)
{
ProductsBLL productAPI = new ProductsBLL();
allProducts = productAPI.GetProducts();
}
// Return the filtered view
allProducts.DefaultView.RowFilter = "CategoryID = " + categoryID;
return allProducts;
}
Beachten Sie das Hinzufügen der Variablen auf Seitenebene, allProducts
. Dieser enthält Informationen zu allen Produkten und wird beim ersten Aufruf der GetProductsInCategory(categoryID)
Methode aufgefüllt. Nachdem sichergestellt wurde, dass das allProducts
Objekt erstellt und aufgefüllt wurde, filtert die Methode die Ergebnisse der DataTable so, dass nur auf die Zeilen zugegriffen werden kann, die CategoryID
dem angegebenen CategoryID
entsprechen. Dieser Ansatz reduziert die Anzahl der Zugriffe auf die Datenbank von N + 1 auf zwei.
Durch diese Erweiterung werden keine Änderungen am gerenderten Markup der Seite vorgenommen, und es werden weniger Datensätze als beim anderen Ansatz zurückgebracht. Die Anzahl der Aufrufe der Datenbank wird einfach reduziert.
Hinweis
Es könnte intuitiv sein, dass die Verringerung der Anzahl der Datenbankzugriffe die Leistung mit Sicherheit verbessern würde. Dies ist jedoch möglicherweise nicht der Fall. Wenn Sie beispielsweise über eine große Anzahl von Produkten verfügen, deren CategoryID
wert ist NULL
, gibt der Aufruf der GetProducts
-Methode eine Anzahl von Produkten zurück, die nie angezeigt werden. Darüber hinaus kann die Rückgabe aller Produkte verschwenderisch sein, wenn Sie nur eine Teilmenge der Kategorien anzeigen, was möglicherweise der Fall ist, wenn Sie paging implementiert haben.
Wenn es wie immer um die Analyse der Leistung von zwei Techniken geht, besteht die einzige sichere Maßnahme darin, kontrollierte Tests auszuführen, die auf die gängigen Fallszenarien Ihrer Anwendung zugeschnitten sind.
Zusammenfassung
In diesem Tutorial haben wir erfahren, wie Ein Datenwebsteuerelement in einem anderen geschachtelt wird. Dabei wurde insbesondere untersucht, wie ein äußerer Repeater ein Element für jede Kategorie mit einem inneren Repeater anzeigt, der die Produkte für jede Kategorie in einer Aufzählungsliste auflistet. Die Standard Herausforderung beim Erstellen einer geschachtelten Benutzeroberfläche besteht darin, auf die richtigen Daten zuzugreifen und an das interne Datenwebsteuerelement zu binden. Es gibt eine Vielzahl von Techniken, von denen wir in diesem Tutorial zwei untersucht haben. Der erste untersuchte Ansatz verwendete eine ObjectDataSource in den äußeren Datenwebsteuerelementen, ItemTemplate
die über seine DataSourceID
-Eigenschaft an das interne Datenwebsteuerelement gebunden war. Die zweite Technik hat über eine Methode in der CodeBehind-Klasse der ASP.NET Seite auf die Daten zugegriffen. Diese Methode kann dann über die Datenbindungssyntax an die Eigenschaft des inneren Datenwebsteuerelements DataSource
gebunden werden.
Während die in diesem Tutorial untersuchte geschachtelte Benutzeroberfläche einen in einem Repeater geschachtelten Repeater verwendet hat, können diese Techniken auf die anderen Datenwebsteuerelemente erweitert werden. Sie können einen Repeater in einer GridView oder eine GridView in einer DataList schachteln usw.
Viel Spaß beim Programmieren!
Zum Autor
Scott Mitchell, Autor von sieben ASP/ASP.NET-Büchern und Gründer von 4GuysFromRolla.com, arbeitet seit 1998 mit Microsoft-Webtechnologien. Scott arbeitet als unabhängiger Berater, Trainer und Autor. Sein neuestes Buch ist Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Er kann unter mitchell@4GuysFromRolla.comoder über seinen Blog erreicht werden, der unter http://ScottOnWriting.NETzu finden ist.
Besonderer Dank an
Diese Tutorialreihe wurde von vielen hilfreichen Prüfern überprüft. Hauptprüfer für dieses Tutorial waren Zack Jones und Liz Shulok. Möchten Sie meine bevorstehenden MSDN-Artikel lesen? Wenn dies der Fall ist, legen Sie eine Zeile unter abmitchell@4GuysFromRolla.com.