Verwenden des UpdatePanel-Steuerelements mit einem Webdienst
Aktualisiert: November 2007
Das UpdatePanel-Steuerelement vereinfacht das Teilrendering von Seiten auf ASP.NET-Webseiten, da die AJAX-Funktionen von ASP.NET asynchrone Postbacks und Aktualisierungen automatisch verwalten. Die AJAX-Funktion geben Ihnen zudem die Möglichkeit, ASP.NET-Webdienste im Browser mithilfe von ECMAScript (JavaScript) aufzurufen. Das Aufrufen eines Webdiensts mithilfe eines Clientskripts bietet unter anderem den Vorteil, dass der Browser beim Warten auf die Beantwortung einer Webdienstanforderung nicht blockiert wird. Die Benutzer können weiterarbeiten und müssen nicht darauf warten, dass der Webdienst die Anforderung verarbeitet hat.
Dieses Lernprogramm zeigt, wie ein Webdienst mithilfe eines UpdatePanel-Steuerelements verwendet wird. Eine JavaScript-Funktion ruft den Webdienst auf, um Daten abzurufen und anschließend DOM-Elemente in einem UpdatePanel-Steuerelement mit den vom Webdienst zurückgegebenen Daten zu füllen. Die abgerufenen Webdienstdaten werden vom Servercode zwischen asynchronen Postbacks gespeichert.
In diesem Thema wird vorausgesetzt, dass Sie mit dem UpdatePanel-Steuerelement und mit Webdiensten vertraut sind. Andernfalls sollten Sie die folgenden Themen wiederholen:
Vorbereitungsmaßnahmen
Zur Implementierung dieser Prozeduren in Ihrer eigenen Entwicklungsumgebung ist Folgendes erforderlich:
Microsoft Visual Studio 2005 oder Visual Web Developer Express Edition.
Eine AJAX-fähige ASP.NET-Website.
Zugriff auf die Datenbank Northwind und eine Verbindungszeichenfolge mit dem Namen NorthwindConnectionString, die in der Datei Web.config definiert ist. Informationen zum Erstellen einer Verbindungszeichenfolge finden Sie unter Gewusst wie: Lesen von Verbindungszeichenfolgen aus der Datei Web.config.
Erstellen eines Webdiensts
Erstellen Sie zunächst einen Webdienst, den Sie aufrufen können.
So erstellen Sie einen Webdienst, der Produktmengen zurückgibt
Erstellen Sie in einer AJAX-fähigen ASP.NET-Website eine neue Webdienstdatei mit dem Namen ProductQueryService.asmx.
Informationen zum Erstellen eines Webdiensts finden Sie unter Aufrufen von Webdiensten vom Clientskript.
Importieren Sie in den Webdienstcode die Namespaces N:System.Data, N:System.Data.SqlClient, System.Configuration und N:System.Web.Script.Services.
Imports System.Data Imports System.Data.SqlClient Imports System.Configuration Imports System.Web.Script.Services
using System.Web.Script.Services; using System.Data; using System.Data.SqlClient; using System.Configuration;
Typen dieser Namespaces werden in der Webdienstmethode verwendet, die Sie erstellen.
Platzieren Sie die ProductQueryService-Klasse in einem Namespace mit dem Namen Samples.
Fügen Sie der Klasse das ScriptServiceAttribute-Attribut hinzu.
Aufgrund dieses Attributs kann der Webdienst vom Clientskript aufgerufen werden.
Ersetzen Sie die HelloWorld-Standardmethode durch die folgende GetProductQuantity-Methode:
<WebMethod()> _ Public Function GetProductQuantity(ByVal productID As String) As String Dim cn As SqlConnection = _ New SqlConnection(ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString) Dim cmd As SqlCommand = _ New SqlCommand("SELECT [UnitsInStock] FROM [Alphabetical list of products] WHERE ([ProductID] = @ProductID)", cn) cmd.Parameters.AddWithValue("productID", productID) Dim unitsInStock As String = "" cn.Open() Using dr As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection) Do While dr.Read() unitsInStock = dr(0).ToString() Loop End Using System.Threading.Thread.Sleep(3000) Return unitsInStock End Function
[WebMethod] public string GetProductQuantity(string productID) { SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString); SqlCommand cmd = new SqlCommand( "SELECT [UnitsInStock] FROM [Alphabetical list of products] WHERE ([ProductID] = @ProductID)", cn); cmd.Parameters.Add("productID", productID); String unitsInStock = ""; cn.Open(); using (SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)) { while (dr.Read()) unitsInStock = dr[0].ToString(); } System.Threading.Thread.Sleep(3000); return unitsInStock; }
Durch den Code werden die folgenden Aufgaben ausgeführt:
Erstellt ein neues SqlConnection-Objekt, das eine Verbindungszeichenfolge mit dem Namen NorthwindConnectionString verwendet.
Erstellt ein neues SqlCommand-Objekt mit einem SQL-Befehl, der die Anzahl vorrätiger Einheiten für eine angegebene Produkt-ID abruft.
Legt den Rückgabewert auf eine Zeichenfolge fest, die als Antwort an den Browser gesendet wird.
Hinweis: In diesem Lernprogramm wird durch die Webmethode eine künstliche Verzögerung eingefügt. In der Praxis würde keine Verzögerung ausgelöst werden. Verzögerungen sind die Folge von zu hohem Datenverkehr auf dem Server oder von Webdienstcode, der eine lange Verarbeitungszeit erfordert (z. B. eine Datenbankabfrage mit einer langen Laufzeit).
Speichern Sie die Änderungen. Drücken Sie anschließend STRG+F5, um die Seite in einem Browser anzuzeigen.
Klicken Sie auf den Link GetProductQuantity, um die Webmethode aufzurufen.
Geben Sie 6 im Feld productID ein, und klicken Sie dann auf Invoke.
Die Produktmenge wird im Browser als XML-Code zurückgegeben. Dies zeigt, dass der Webdienst wie vorgesehen funktioniert.
<%@ WebService Language="VB" Class="Samples.ProductQueryService" %> Imports System Imports System.Web Imports System.Web.Services Imports System.Web.Services.Protocols Imports System.Data Imports System.Data.SqlClient Imports System.Configuration Imports System.Web.Script.Services Namespace Samples <ScriptService()> _ <WebService(Namespace:="http://tempuri.org/")> _ <WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _ Public Class ProductQueryService Inherits System.Web.Services.WebService <WebMethod()> _ Public Function GetProductQuantity(ByVal productID As String) As String Dim cn As SqlConnection = _ New SqlConnection(ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString) Dim cmd As SqlCommand = _ New SqlCommand("SELECT [UnitsInStock] FROM [Alphabetical list of products] WHERE ([ProductID] = @ProductID)", cn) cmd.Parameters.AddWithValue("productID", productID) Dim unitsInStock As String = "" cn.Open() Using dr As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection) Do While dr.Read() unitsInStock = dr(0).ToString() Loop End Using System.Threading.Thread.Sleep(3000) Return unitsInStock End Function End Class End Namespace
<%@ WebService Language="C#" Class="Samples.ProductQueryService" %> using System; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; using System.Web.Script.Services; using System.Data; using System.Data.SqlClient; using System.Configuration; namespace Samples { [ScriptService] [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class ProductQueryService : System.Web.Services.WebService { [WebMethod] public string GetProductQuantity(string productID) { SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString); SqlCommand cmd = new SqlCommand( "SELECT [UnitsInStock] FROM [Alphabetical list of products] WHERE ([ProductID] = @ProductID)", cn); cmd.Parameters.Add("productID", productID); String unitsInStock = ""; cn.Open(); using (SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)) { while (dr.Read()) unitsInStock = dr[0].ToString(); } System.Threading.Thread.Sleep(3000); return unitsInStock; } } }
Erstellen von JavaScript-Code zum Aufrufen des Webdiensts
In diesem Verfahren erstellen Sie eine JavaScript-Datei, die den Webdienst aufruft, den Sie im vorherigen Verfahren erstellt haben.
So erstellen Sie eine JavaScript-Datei, die den Webdienst verwendet
Erstellen Sie eine neue JScript-Datei mit dem Namen ProductQueryScript.js.
Fügen Sie dieser Datei das folgende Skript hinzu:
function GetQuantity(productID, elemToUpdate, productLabelElem, buttonElem) { var userContext = [productID, elemToUpdate, productLabelElem, buttonElem]; Samples.ProductQueryService.GetProductQuantity(productID, OnSucceeded, null, userContext, null); $get(buttonElem).value = "Retrieving value..."; } function OnSucceeded(result, userContext) { var productID = userContext[0]; var elemToUpdate = userContext[1]; var productLabelElem = userContext[2]; var buttonElem = userContext[3]; $get(buttonElem).value = "Get Quantity from Web Service"; if ($get(elemToUpdate) !== null && $get(productLabelElem).innerHTML == productID) { $get(elemToUpdate).value = result; } }
function GetQuantity(productID, elemToUpdate, productLabelElem, buttonElem) { var userContext = [productID, elemToUpdate, productLabelElem, buttonElem]; Samples.ProductQueryService.GetProductQuantity(productID, OnSucceeded, null, userContext, null); $get(buttonElem).value = "Retrieving value..."; } function OnSucceeded(result, userContext) { var productID = userContext[0]; var elemToUpdate = userContext[1]; var productLabelElem = userContext[2]; var buttonElem = userContext[3]; $get(buttonElem).value = "Get Quantity from Web Service"; if ($get(elemToUpdate) !== null && $get(productLabelElem).innerHTML == productID) { $get(elemToUpdate).value = result; } }
Mit diesem Skript werden die folgenden Aufgaben ausgeführt:
Erstellt eine Funktion mit dem Namen GetQuantity, die die GetProductQuantity-Webdienstmethode aufruft.
Erstellt eine Funktion mit dem Namen OnSucceeded, die aufgerufen wird, wenn der Webdienstaufruf ein Ergebnis zurückgibt.
Erstellen einer Webseite zum Anzeigen von Daten
Im nächsten Schritt erstellen Sie eine Webseite, die ein UpdatePanel-Steuerelement enthält. Steuerelemente im UpdatePanel-Steuerelement zeigen Produktinformationen aus der Datenbank Northwind an.
So erstellen Sie eine Webseite, auf der Produkte angezeigt werden
Erstellen Sie eine neue Webseite, und wechseln Sie in die Entwurfsansicht.
Doppelklicken Sie auf der Registerkarte AJAX-Erweiterungen der Toolbox auf das ScriptManager-Steuerelement, um es der Seite hinzuzufügen.
Doppelklicken Sie in der Toolbox auf das UpdatePanel-Steuerelement, um der Seite ein UpdatePanel-Steuerelement hinzuzufügen.
Klicken Sie in das UpdatePanel-Steuerelement, und doppelklicken Sie dann in der Toolbox auf der Registerkarte Daten auf das DataList-Steuerelement.
Wählen Sie im Bereich DataList-Aufgaben in der Liste Datenquelle auswählen die Option <Neue Datenquelle...> aus.
Hinweis: Wenn der Bereich DataList-Aufgaben nicht angezeigt wird, klicken Sie mit der rechten Maustaste auf das DataList-Steuerelement, und wählen Sie Smarttag anzeigen aus.
Der Assistent zum Konfigurieren von Datenquellen wird angezeigt.
Wählen Sie Datenbank aus, bestätigen Sie den Standardnamen SqlDataSource1, und klicken Sie dann auf OK.
Wählen Sie in der Liste Über welche Datenverbindung soll die Anwendung eine Verbindung mit der Datenbank herstellen den Eintrag NorthwindConnectionString aus, und klicken Sie dann auf Weiter.
Wählen Sie unter Wie möchten Sie Daten aus der Datenbank abrufen die Option Spalten von einer Tabelle oder Ansicht angeben, wählen Sie in der Liste die Option Products aus, und wählen Sie dann in der Liste Spalten die Einträge ProductID und ProductName aus.
Klicken Sie auf die Schaltfläche WHERE.
Das Dialogfeld WHERE-Klausel hinzufügen wird angezeigt.
Wählen Sie in der Liste Spalten den Eintrag CategoryID aus, und wählen Sie in der Liste Quelle den Eintrag Keine aus.
Geben Sie im Abschnitt Parametereigenschaften des Dialogfelds im Textfeld Wert den Wert 1 ein.
Klicken Sie auf Hinzufügen, um der SQL-Anweisung die WHERE-Klausel hinzuzufügen.
Klicken Sie auf OK, um das Dialogfeld WHERE-Klausel hinzufügen zu schließen.
Klicken Sie auf Weiter, und klicken Sie dann auf Fertig stellen, um den Assistenten zu schließen.
Wechseln Sie zur Quellenansicht, und überprüfen Sie, ob das SqlDataSource-Steuerelement dem folgenden Beispiel ähnelt:
<asp:SqlDataSource ID="SqlDataSource1" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="SELECT [ProductName], [ProductID] FROM [Alphabetical list of products] WHERE ([CategoryID] = @CategoryID)"> <SelectParameters> <asp:Parameter DefaultValue="1" Name="CategoryID" Type="Int32" /> </SelectParameters> </asp:SqlDataSource>
<asp:SqlDataSource ID="SqlDataSource1" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="SELECT [ProductName], [ProductID] FROM [Alphabetical list of products] WHERE ([CategoryID] = @CategoryID)"> <SelectParameters> <asp:Parameter DefaultValue="1" Name="CategoryID" Type="Int32" /> </SelectParameters> </asp:SqlDataSource>
Wechseln Sie in die Entwurfsansicht.
Wählen Sie das DataList-Steuerelement aus, und klicken Sie im Bereich DataList-Aufgaben auf Vorlagen bearbeiten.
Fügen Sie zwei Button-Steuerelemente zum UpdatePanel-Steuerelement außerhalb des DataList-Steuerelements hinzu.
Legen Sie die ID-Eigenschaft der ersten Schaltfläche auf Category1Button und deren Text-Eigenschaft auf Kategorie 1 fest. Legen Sie die ID-Eigenschaft der zweiten Schaltfläche auf Category2Button und deren Text-Eigenschaft auf Kategorie 2 fest.
Wählen Sie das UpdatePanel-Steuerelement aus, legen Sie im Eigenschaftenfenster die UpdateMode-Eigenschaft auf Conditional fest, und legen Sie die ChildrenAsTriggers-Eigenschaft auf false fest.
Klicken Sie im Feld Trigger auf die Auslassungspunkte (…), und fügen Sie im Dialogfeld UpdatePanelTrigger-Auflistungs-Editor jede Kategorieschaltfläche als asynchronen Postbacktrigger hinzu.
Legen Sie den Click-Ereignishandler für die erste Schaltfläche auf Category1Button_Click fest, und legen Sie den Click-Ereignishandler für die zweite Schaltfläche auf Category2Button_Click fest.
Wechseln Sie zur Quellenansicht, und erstellen Sie für die beiden Schaltflächen die folgenden Ereignishandler:
Protected Sub Category1Button_Click(ByVal sender As Object, ByVal e As System.EventArgs) SqlDataSource1.SelectParameters(0).DefaultValue = "1" End Sub Protected Sub Category2Button_Click(ByVal sender As Object, ByVal e As System.EventArgs) SqlDataSource1.SelectParameters(0).DefaultValue = "2" End Sub
protected void Category1Button_Click(object sender, EventArgs e) { SqlDataSource1.SelectParameters[0].DefaultValue = "1"; } protected void Category2Button_Click(object sender, EventArgs e) { SqlDataSource1.SelectParameters[0].DefaultValue = "2"; }
Der Code des Ereignishandlers legt den CategoryID-Parameter der SelectParameters-Auflistung im SqlDataSource-Steuerelement je nach gedrückter Schaltfläche fest. So können die Benutzer zwischen zwei Kategorien umschalten.
Speichern Sie die Änderungen, und drücken Sie STRG+F5, um die Seite in einem Browser anzuzeigen.
Klicken Sie auf Kategorie 2, und überprüfen Sie, ob neue Informationen auf der Seite angezeigt werden und ob nicht die gesamte Seite aktualisiert wird.
Hinweis: Schließen Sie die Seite nicht.
<%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script > Protected Sub Category1Button_Click(ByVal sender As Object, ByVal e As System.EventArgs) SqlDataSource1.SelectParameters(0).DefaultValue = "1" End Sub Protected Sub Category2Button_Click(ByVal sender As Object, ByVal e As System.EventArgs) SqlDataSource1.SelectParameters(0).DefaultValue = "2" End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head > <title>Products Display</title> </head> <body> <form id="form1" > <div> <asp:ScriptManager ID="ScriptManager1" > </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" ChildrenAsTriggers="False" UpdateMode="Conditional"> <ContentTemplate> <asp:Button ID="Category1Button" Text="Category 1" OnClick="Category1Button_Click" /> <asp:Button ID="Category2Button" OnClick="Category2Button_Click" Text="Category 2" /> <asp:DataList ID="DataList1" DataKeyField="ProductID" DataSourceID="SqlDataSource1" Width="231px"> <ItemTemplate> ProductName: <asp:Label ID="ProductNameLabel" Text='<%# Eval("ProductName") %>'> </asp:Label><br /> ProductID: <asp:Label ID="ProductIDLabel" Text='<%# Eval("ProductID") %>'></asp:Label><br /> <br /> </ItemTemplate> </asp:DataList> <asp:SqlDataSource ID="SqlDataSource1" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="SELECT [ProductName], [ProductID] FROM [Alphabetical list of products] WHERE ([CategoryID] = @CategoryID)"> <SelectParameters> <asp:Parameter DefaultValue="1" Name="CategoryID" Type="Int32" /> </SelectParameters> </asp:SqlDataSource> </ContentTemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="Category1Button" /> <asp:AsyncPostBackTrigger ControlID="Category2Button" /> </Triggers> </asp:UpdatePanel> </div> </form> </body> </html>
<%@ Page Language="C#" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script > protected void Category1Button_Click(object sender, EventArgs e) { SqlDataSource1.SelectParameters[0].DefaultValue = "1"; } protected void Category2Button_Click(object sender, EventArgs e) { SqlDataSource1.SelectParameters[0].DefaultValue = "2"; } </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head > <title>Products Display</title> </head> <body> <form id="form1" > <div> <asp:ScriptManager ID="ScriptManager1" > </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" ChildrenAsTriggers="False" UpdateMode="Conditional"> <ContentTemplate> <asp:Button ID="Category1Button" Text="Category 1" OnClick="Category1Button_Click" /> <asp:Button ID="Category2Button" OnClick="Category2Button_Click" Text="Category 2" /> <asp:DataList ID="DataList1" DataKeyField="ProductID" DataSourceID="SqlDataSource1" Width="231px"> <ItemTemplate> ProductName: <asp:Label ID="ProductNameLabel" Text='<%# Eval("ProductName") %>'> </asp:Label><br /> ProductID: <asp:Label ID="ProductIDLabel" Text='<%# Eval("ProductID") %>'></asp:Label><br /> <br /> </ItemTemplate> </asp:DataList> <asp:SqlDataSource ID="SqlDataSource1" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="SELECT [ProductName], [ProductID] FROM [Alphabetical list of products] WHERE ([CategoryID] = @CategoryID)"> <SelectParameters> <asp:Parameter DefaultValue="1" Name="CategoryID" Type="Int32" /> </SelectParameters> </asp:SqlDataSource> </ContentTemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="Category1Button" /> <asp:AsyncPostBackTrigger ControlID="Category2Button" /> </Triggers> </asp:UpdatePanel> </div> </form> </body> </html>
Aufrufen eines Webdiensts zum Abrufen der Daten
Jetzt rufen Sie den Webdienst über die zuvor erstellte JavaScript-Datei auf. Der JavaScript-Code verwendet die zurückgegebenen Daten zum Auffüllen von DOM-Elementen im UpdatePanel-Steuerelement. Der Servercode auf der Seite speichert die Daten, die vom Webdienst aufgefüllt werden, und fügt die Daten dem Ansichtszustand der Seite hinzu. Damit bleiben die Daten in allen nachfolgenden asynchronen Postbacks erhalten.
So verwenden Sie einen Webdienst zum Zurückgeben von Produktmengen
Wechseln Sie auf der Seite zur Entwurfsansicht.
Wählen Sie das DataList-Steuerelement aus, und klicken Sie im Bereich DataList-Aufgaben auf Vorlagen bearbeiten.
Fügen Sie der Elementvorlage ein TextBox-Steuerelement und ein Button-Steuerelement hinzu.
Fügen Sie die neuen Steuerelemente in der Vorlage unter dem vorhandenen Text und den vorhandenen Bezeichnungen hinzu.
Wählen Sie die Schaltfläche aus, und legen Sie deren Text-Eigenschaft im Eigenschaftenfenster auf Menge von Webdienst abrufen fest.
Die Elementvorlage des DataList-Steuerelements sollte ungefähr der folgenden Abbildung entsprechen.
Wählen Sie das DataList-Steuerelement aus, und doppelklicken Sie anschließend im Eigenschaftenfenster auf der Registerkarte Ereignisse auf das ItemDataBound-Ereignis.
Fügen Sie den folgenden Code hinzu:
Protected Sub DataList1_ItemDataBound(ByVal sender As Object, ByVal e As DataListItemEventArgs) Dim label As Label = CType(e.Item.FindControl("ProductIDLabel"), Label) Dim button As Button = CType(e.Item.FindControl("Button1"), Button) Dim textbox As TextBox = CType(e.Item.FindControl("TextBox1"), TextBox) button.OnClientClick = "GetQuantity(" & label.Text & ",'" & textbox.ClientID & "','" & _ label.ClientID + "','" & button.ClientID & "')" Dim ProductInfo As SortedList = Me.ProductInfo If (ProductInfo.ContainsKey(label.Text)) Then textbox.Text = ProductInfo(label.Text).ToString() End If End Sub
protected void DataList1_ItemDataBound(object sender, DataListItemEventArgs e) { Label label = (Label)e.Item.FindControl("ProductIDLabel"); Button button = (Button)e.Item.FindControl("Button1"); TextBox textbox = (TextBox)e.Item.FindControl("TextBox1"); button.OnClientClick = "GetQuantity(" + label.Text + ",'" + textbox.ClientID + "','" + label.ClientID + "','" + button.ClientID + "')"; SortedList ProductInfo = this.ProductInfo; if (ProductInfo.ContainsKey(label.Text)) { textbox.Text = ProductInfo[label.Text].ToString(); } }
Der Code legt Eigenschaften für Steuerelemente in jedem DataListItem-Objekt folgendermaßen fest:
Die OnClientClick-Eigenschaft der Schaltfläche ruft eine JavaScript-Funktion auf, die wiederum den Webdienst aufruft.
Der Wert des Textfelds wird festgelegt, wenn eine Nachverfolgungseigenschaft mit dem Namen ProductInfo einen Schlüssel für die Produkt-ID enthält. Die ProductInfo-Eigenschaft wird im nächsten Schritt dieses Verfahrens definiert.
Fügen Sie der Seite eine Eigenschaft mit dem Namen ProductInfo hinzu.
Protected Property ProductInfo() As SortedList Get If ViewState("ProductInfo") IsNot Nothing Then Return CType(ViewState("ProductInfo"), SortedList) Else Return New SortedList() End If End Get Set(ByVal value As SortedList) ViewState("ProductInfo") = value End Set End Property
protected SortedList ProductInfo { get { return (SortedList)(ViewState["ProductInfo"] ?? new SortedList()); } set { ViewState["ProductInfo"] = value; } }
Diese Eigenschaft ist ein SortedList-Objekt, das Daten verfolgt, die der Seite vom Webdienst hinzugefügt wurden. Beim erstmaligen Rendern der Seite ist die Liste leer. Bei späteren asynchronen Postbacks werden der Liste unter Umständen Elemente hinzugefügt.
Fügen Sie den folgenden Page_Load-Ereignishandler hinzu:
Protected Sub Page_Load() If (ScriptManager1.IsInAsyncPostBack) Then Dim ProductInfo As SortedList = Me.ProductInfo For Each d As DataListItem In DataList1.Items Dim label As Label = CType(d.FindControl("ProductIDLabel"), Label) Dim textbox As TextBox = CType(d.FindControl("TextBox1"), TextBox) If (textbox.Text.Length > 0) Then ProductInfo(label.Text) = textbox.Text End If Next Me.ProductInfo = ProductInfo End If End Sub
protected void Page_Load(object sender, EventArgs e) { if (ScriptManager1.IsInAsyncPostBack) { SortedList ProductInfo = this.ProductInfo; foreach (DataListItem d in DataList1.Items) { Label label = (Label)d.FindControl("ProductIDLabel"); TextBox textbox = (TextBox)d.FindControl("TextBox1"); if (textbox.Text.Length > 0) { ProductInfo[label.Text] = textbox.Text; } } this.ProductInfo = ProductInfo; } }
Der Code überprüft, ob es sich bei der Anforderung um ein asynchrones Postback handelt. Ist dies der Fall, werden vom Webdienst hinzugefügte Datenelemente der ProductInfo-Eigenschaft hinzugefügt. So können diese im Ansichtszustand verfolgt und bei späteren Teilaktualisierungen von Seiten im UpdatePanel angezeigt werden. Wenn die Datenelemente nicht im Ansichtszustand verfolgt werden, bleiben sie in späteren asynchronen Postbacks nicht erhalten.
Wechseln Sie in die Entwurfsansicht.
Wählen Sie das ScriptManager-Steuerelement aus.
Wählen Sie im Eigenschaftenfenster die Services-Eigenschaft aus, und klicken Sie auf die Auslassungspunkte (…), um das Dialogfeld ServiceReference-Auflistungs-Editor anzuzeigen.
Klicken Sie zum Hinzufügen eines Serviceverweises auf Hinzufügen.
Legen Sie die Path-Eigenschaft des Dienstverweises auf ProductQueryService.asmx fest. Dies ist der zuvor erstellte Webdienst.
Das Hinzufügen eines Dienstverweises bewirkt, dass das ScriptManager-Steuerelement Clientproxyklassen generiert, sodass der Webdienst mithilfe von JavaScript aufgerufen werden kann.
Klicken Sie zum Schließen des Dialogfelds ServiceReference-Auflistungs-Editor auf OK.
Wählen Sie das ScriptManager-Steuerelement aus, wählen Sie anschließend im Eigenschaftenfenster die Scripts-Eigenschaft aus, und klicken Sie auf die Auslassungspunkte (…), um das Dialogfeld ScriptReference-Auflistungs-Editor anzuzeigen.
Klicken Sie zum Hinzufügen eines Skriptverweises auf Hinzufügen.
Legen Sie die Path-Eigenschaft des Skriptverweises auf die zuvor erstellte JavaScript-Datei ProduktQueryScript.js fest.
Das Hinzufügen eines Skriptverweises bewirkt, dass das ScriptManager-Steuerelement das Skript nach dem Laden der Microsoft AJAX Library einfügt.
Klicken Sie zum Schließen des Dialogfelds SkriptReference-Auflistungs-Editor auf OK.
Speichern Sie die Änderungen, und drücken Sie STRG+F5, um die Seite in einem Browser anzuzeigen.
Auf der Seite werden die Produkte der Datenbank Northwind angezeigt, deren Kategorie-ID den Wert 1 hat. Die Textfelder neben den einzelnen Produkten sind leer, da keine Webdienste aufgerufen wurden.
<%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script > Protected Property ProductInfo() As SortedList Get If ViewState("ProductInfo") IsNot Nothing Then Return CType(ViewState("ProductInfo"), SortedList) Else Return New SortedList() End If End Get Set(ByVal value As SortedList) ViewState("ProductInfo") = value End Set End Property Protected Sub Category1Button_Click(ByVal sender As Object, ByVal e As EventArgs) SqlDataSource1.SelectParameters(0).DefaultValue = "1" End Sub Protected Sub Category2Button_Click(ByVal sender As Object, ByVal e As EventArgs) SqlDataSource1.SelectParameters(0).DefaultValue = "2" End Sub Protected Sub DataList1_ItemDataBound(ByVal sender As Object, ByVal e As DataListItemEventArgs) Dim label As Label = CType(e.Item.FindControl("ProductIDLabel"), Label) Dim button As Button = CType(e.Item.FindControl("Button1"), Button) Dim textbox As TextBox = CType(e.Item.FindControl("TextBox1"), TextBox) button.OnClientClick = "GetQuantity(" & label.Text & ",'" & textbox.ClientID & "','" & _ label.ClientID + "','" & button.ClientID & "')" Dim ProductInfo As SortedList = Me.ProductInfo If (ProductInfo.ContainsKey(label.Text)) Then textbox.Text = ProductInfo(label.Text).ToString() End If End Sub Protected Sub Page_Load() If (ScriptManager1.IsInAsyncPostBack) Then Dim ProductInfo As SortedList = Me.ProductInfo For Each d As DataListItem In DataList1.Items Dim label As Label = CType(d.FindControl("ProductIDLabel"), Label) Dim textbox As TextBox = CType(d.FindControl("TextBox1"), TextBox) If (textbox.Text.Length > 0) Then ProductInfo(label.Text) = textbox.Text End If Next Me.ProductInfo = ProductInfo End If End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head > <title>Products Display</title> </head> <body> <form id="form1" > <div> <asp:ScriptManager ID="ScriptManager1" > <Services> <asp:ServiceReference Path="ProductQueryService.asmx" /> </Services> <Scripts> <asp:ScriptReference Path="ProductQueryScript.js" /> </Scripts> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" ChildrenAsTriggers="False" UpdateMode="Conditional"> <ContentTemplate> <asp:Button ID="Category1Button" Text="Category 1" OnClick="Category1Button_Click" /> <asp:Button ID="Category2Button" OnClick="Category2Button_Click" Text="Category 2" /> <asp:DataList ID="DataList1" DataKeyField="ProductID" DataSourceID="SqlDataSource1" Width="400px" OnItemDataBound="DataList1_ItemDataBound"> <ItemTemplate> ProductName: <asp:Label ID="ProductNameLabel" Text='<%# Eval("ProductName") %>'> </asp:Label><br /> ProductID: <asp:Label ID="ProductIDLabel" Text='<%# Eval("ProductID") %>'></asp:Label><br /> <asp:TextBox ID="TextBox1" ></asp:TextBox> <asp:Button ID="Button1" Text="Get Quantity from Web Service" /><br /> </ItemTemplate> </asp:DataList> <asp:SqlDataSource ID="SqlDataSource1" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="SELECT [ProductName], [ProductID] FROM [Alphabetical list of products] WHERE ([CategoryID] = @CategoryID)"> <SelectParameters> <asp:Parameter DefaultValue="1" Name="CategoryID" Type="Int32" /> </SelectParameters> </asp:SqlDataSource> </ContentTemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="Category1Button" /> <asp:AsyncPostBackTrigger ControlID="Category2Button" /> </Triggers> </asp:UpdatePanel> </div> </form> </body> </html>
<%@ Page Language="C#" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script > protected SortedList ProductInfo { get { return (SortedList)(ViewState["ProductInfo"] ?? new SortedList()); } set { ViewState["ProductInfo"] = value; } } protected void Category1Button_Click(object sender, EventArgs e) { SqlDataSource1.SelectParameters[0].DefaultValue = "1"; } protected void Category2Button_Click(object sender, EventArgs e) { SqlDataSource1.SelectParameters[0].DefaultValue = "2"; } protected void DataList1_ItemDataBound(object sender, DataListItemEventArgs e) { Label label = (Label)e.Item.FindControl("ProductIDLabel"); Button button = (Button)e.Item.FindControl("Button1"); TextBox textbox = (TextBox)e.Item.FindControl("TextBox1"); button.OnClientClick = "GetQuantity(" + label.Text + ",'" + textbox.ClientID + "','" + label.ClientID + "','" + button.ClientID + "')"; SortedList ProductInfo = this.ProductInfo; if (ProductInfo.ContainsKey(label.Text)) { textbox.Text = ProductInfo[label.Text].ToString(); } } protected void Page_Load(object sender, EventArgs e) { if (ScriptManager1.IsInAsyncPostBack) { SortedList ProductInfo = this.ProductInfo; foreach (DataListItem d in DataList1.Items) { Label label = (Label)d.FindControl("ProductIDLabel"); TextBox textbox = (TextBox)d.FindControl("TextBox1"); if (textbox.Text.Length > 0) { ProductInfo[label.Text] = textbox.Text; } } this.ProductInfo = ProductInfo; } } </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head > <title>Products Display</title> </head> <body> <form id="form1" > <div> <asp:ScriptManager ID="ScriptManager1" > <Services> <asp:ServiceReference Path="ProductQueryService.asmx" /> </Services> <Scripts> <asp:ScriptReference Path="ProductQueryScript.js" /> </Scripts> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" ChildrenAsTriggers="False" UpdateMode="Conditional"> <ContentTemplate> <asp:Button ID="Category1Button" Text="Category 1" OnClick="Category1Button_Click" /> <asp:Button ID="Category2Button" OnClick="Category2Button_Click" Text="Category 2" /> <asp:DataList ID="DataList1" DataKeyField="ProductID" DataSourceID="SqlDataSource1" Width="400px" OnItemDataBound="DataList1_ItemDataBound"> <ItemTemplate> ProductName: <asp:Label ID="ProductNameLabel" Text='<%# Eval("ProductName") %>'> </asp:Label><br /> ProductID: <asp:Label ID="ProductIDLabel" Text='<%# Eval("ProductID") %>'></asp:Label><br /> <asp:TextBox ID="TextBox1" ></asp:TextBox> <asp:Button ID="Button1" Text="Get Quantity from Web Service" /><br /> </ItemTemplate> </asp:DataList> <asp:SqlDataSource ID="SqlDataSource1" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="SELECT [ProductName], [ProductID] FROM [Alphabetical list of products] WHERE ([CategoryID] = @CategoryID)"> <SelectParameters> <asp:Parameter DefaultValue="1" Name="CategoryID" Type="Int32" /> </SelectParameters> </asp:SqlDataSource> </ContentTemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="Category1Button" /> <asp:AsyncPostBackTrigger ControlID="Category2Button" /> </Triggers> </asp:UpdatePanel> </div> </form> </body> </html>
Überprüfen, ob Daten während asynchroner Postbacks beibehalten werden
Jetzt können Sie sehen, wie Daten vom Webdienst während asynchroner Postbacks bestehen bleiben.
So überprüfen Sie, ob Webdienstdaten während asynchroner Postbacks bestehen bleiben
Wenn die Seite noch nicht ausgeführt wird, drücken Sie STRG+F5, um die Seite auszuführen.
Klicken Sie für ein beliebiges Produkt aus der Liste auf die Schaltfläche Menge von Webdienst abrufen, und warten Sie, bis der Wert im Textfeld angezeigt wird.
Klicken Sie auf die Schaltfläche Kategorie 2.
Klicken Sie auf die Schaltfläche Kategorie 1.
Sie sehen, dass der vom Webdienst zuvor zurückgegebene Wert weiterhin angezeigt wird, auch nach den asynchronen Postbacks.
Zusammenfassung
In diesem Lernprogramm wurde ein Beispiel für die Verwendung eines UpdatePanel-Steuerelements in einem Webdienst vorgeführt, der vom JavaScript-Code im Browser aufgerufen wird. Der Webdienst gibt Daten zurück, die im UpdatePanel-Steuerelement angezeigt werden.
Das Aufrufen des Webdiensts im Clientskript und das Auffüllen von DOM-Elementen mit den zurückgegebenen Daten führt mit oder ohne UpdatePanel-Steuerelemente zum gleichen Ergebnis. Wenn eine Seite ein Postback ausführt oder wenn ein asynchrones Postback erfolgt, gehen die zuvor mithilfe des Clientskripts angezeigten Daten verloren. Um dieses Problem zu vermeiden, können Sie Servercode verwenden, der die Daten beibehält, indem er sie in einen Ansichtszustand eingliedert. So können Sie die Daten während späterer Postbacks beibehalten. Wenn die Daten des Webdiensts in DOM-Elementen außerhalb von UpdatePanel-Steuerelementen angezeigt werden und die Daten während asynchroner Postbacks nicht erhalten bleiben sollen, müssen Sie keinen Servercode bereitstellen.
Da sich die Schaltfläche, durch die der Aufruf des Webdiensts ausgelöst wurde, innerhalb des UpdatePanel-Steuerelements befindet, wird die ChildrenAsTriggers-Eigenschaft auf false festgelegt. Weitere Postback-Steuerelemente innerhalb des Bereichs werden als Trigger für den Bereich definiert.