Использование элемента управления UpdatePanel c веб-службой

Обновлен: Ноябрь 2007

Элемент управления UpdatePanel упрощает частичную отрисовку страниц ASP.NET, поскольку функциональность AJAX в ASP.NET осуществляет обработку асинхронных запросов и обновлений обратной передачи автоматически. Функциональность AJAX также позволяет осуществлять вызовы веб-служб ASP.NET, используя ECMAScript (JavaScript) в обозревателе. Одним из преимуществ вызова веб-служб с помощью клиентского сценария является то, что ожидание ответа от веб-службы не приводит к блокировке обозревателя. Пользователи могут продолжать работу, не дожидаясь, когда веб-служба завершит обработку запроса.

В этом руководстве демонстрируется, как использовать веб-службу с помощью элемента управления UpdatePanel. Функция JavaScript вызывает веб-службу, чтобы извлечь данные, которые потом использует для заполнения элементов DOM в элементе управления UpdatePanel. Серверный код сохраняет полученные от веб-службы данные в промежутках между асинхронной обратной передачей.

В этом разделе предполагается, что вы знакомы с элементом управления UpdatePanel и веб-службами. В противном случае ознакомьтесь со следующими разделами:

Обязательные компоненты

Для реализации процедур в собственной среде разработки потребуется:

Создание веб-службы

Для начала будет создана вызываемая веб-служба.

Создание веб-службы, возвращающей количество продукции

  1. На веб-узле ASP.NET, поддерживающем AJAX, создайте новый файл веб-службы с именем ProductQueryService.asmx.

    Дополнительные сведения о создании веб-служб см. в разделе Вызов веб-служб из клиентского сценария.

  2. В коде веб-службы импортируйте пространства имен N:System.Data, N:System.Data.SqlClient, System.Configuration и 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;
    

    Типы из этих пространств имен будут использоваться в методе веб-службы, который будет создан в дальнейшем.

  3. Поместите класс ProductQueryService в пространство имен Samples.

  4. Добавьте в класс атрибут ScriptServiceAttribute.

    Этот атрибут позволяет вызывать веб-службу из клиентского сценария.

  5. Замените метод HelloWorld, определенный по умолчанию, следующим методом GetProductQuantity:

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

    Этот код выполняет следующие задачи:

    • Создает новый объект SqlConnection, использующий строку соединения NorthwindConnectionString.

    • Создает новый объект SqlCommand, содержащий команду SQL для извлечения числа единиц хранения по заданному идентификатору товара.

    • Заносит в возвращаемое значение строку, которая будет использоваться в качестве ответа, отправляемого обозревателю.

      Bb398898.alert_note(ru-ru,VS.90).gifПримечание.

      В этом руководстве в методе веб-службы вводится искусственная задержка. На практике в такой задержке нет необходимости. Вместо этого все задержки будут возникать из-за серверного трафика или долговременного выполнения кода метода веб-службы, например, в результате длительного запроса к базе данных.

  6. Сохраните изменения и нажмите CTRL + F5 для просмотра страницы в обозревателе.

  7. Щелкните ссылку GetProductQuantity, чтобы вызвать метод веб-службы.

  8. В поле productID введите значение 6 и нажмите кнопку Invoke.

    Количество товаров будет возвращено в обозреватель в формате XML. Это показывает, что веб-служба работает, как задумано.

    <%@ 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;
            }
        }
    }
    

Создание кода JavaScript, вызывающего веб-службу

В этой процедуре будет создан файл JavaScript, вызывающий веб-службу, созданную в предыдущей процедуре.

Создание файла JavaScript, использующего веб-службу

  1. Создайте новый файл JScript с именем ProductQueryScript.js.

  2. Добавьте следующий сценарий в файл:

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

    Сценарий выполняет следующие задачи:

    • Создайте функцию GetQuantity, вызывающую метод GetProductQuantity веб-службы.

    • Создайте функцию OnSucceeded, которая будет вызываться, когда вызов веб-службы возвращает результат.

Создание веб-страницы для отображения данных

Далее будет создана веб-страница, содержащая элемент управления UpdatePanel. Элементы управления внутри элемента управления UpdatePanel будут отображать сведения о товарах из базы данных "Northwind".

Создание веб-страницы для отображения товаров

  1. Создайте новую веб-страницу и переключитесь в режим конструктора.

  2. На вкладке AJAX-расширения панели элементов дважды щелкните элемент управления ScriptManager, чтобы добавить его на страницу.

  3. Дважды щелкните элемент управления UpdatePanel в панели элементов, чтобы добавить его на страницу.

    Урок UpdatePanel

  4. Щелкните внутри элемента управления UpdatePanel и на вкладке Данные в панели элементов дважды щелкните элемент управления DataList.

  5. В панели Задачи DataList выберите в списке Выбор источника данных пункт <Новый источник данных…>.

    Bb398898.alert_note(ru-ru,VS.90).gifПримечание.

    Если панель Задачи DataList не отображается, щелкните правой кнопкой мыши элемент управления DataList и выберите команду Показать смарт-тег.

    Появится мастер настройки источника данных.

  6. Выберите параметр База данных, оставьте заданное по умолчанию имя SqlDataSource1 и нажмите кнопку ОК.

  7. В списке Какое подключение ваше приложение должно использовать для работы с базой данных? выберите NorthwindConnectionString и нажмите кнопку Далее.

  8. В списке How would you like to retrieve data from your database выберите Specify columns from a table or view, выберите в списке таблицу Товары, а в списке Столбцы выберите Код товара и Наименование.

  9. Нажмите кнопку WHERE.

    Будет отображено диалоговое окно Добавить предложение WHERE.

  10. В списке Столбцы выберите Категория, а в списке Источник выберите Нет.

  11. В разделе Свойства параметра диалогового окна в текстовом поле Значение введите 1.

  12. Нажмите кнопку Добавить, чтобы добавить предложение WHERE в инструкцию SQL.

  13. Нажмите кнопку ОК, чтобы закрыть диалоговое окно Добавить предложение WHERE.

    Урок UpdatePanel

  14. Нажмите кнопку Далее, а затем кнопку Готово, чтобы закрыть мастер.

  15. Переключитесь в режим исходного кода и удостоверьтесь в том, что элемент управления SqlDataSource походит на следующий пример:

    <asp:SqlDataSource ID="SqlDataSource1" runat="server" 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" runat="server" 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>
    
  16. Перейдите в режим конструктора.

  17. Выберите элемент управления DataList и в панели Задачи DataList выберите Редактирование шаблонов.

  18. Добавьте два элемента управления Button в элемент управления UpdatePanel так, чтобы они находились вне элемента управления DataList.

  19. .Задайте для свойства ID первой кнопки значение Category1Button, а для свойства Text этой же кнопки — значение Категория 1. Задайте для свойства ID второй кнопки значение Category2Button, а для свойства Text этой же кнопки — значение Категория 2.

    Урок UpdatePanel

  20. Выберите элемент управления UpdatePanel и в окне "Свойства" задайте для свойства UpdateMode значение Conditional, а для свойства ChildrenAsTriggers — значение false.

  21. В поле Triggers нажмите кнопку с многоточием ("…") и добавьте в диалоговом окне Редактор коллекции UpdatePanel Trigger обе кнопки категорий в качестве триггеров асинхронной обратной передачи.

    Урок UpdatePanel

  22. В качестве обработчика событий Click для первой кнопки выберите Category1Button_Click, а в качестве обработчика событий Click для второй кнопки — Category2Button_Click.

  23. Переключитесь в режим исходного кода и создайте следующие обработчики событий для обеих кнопок:

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

    Код обработчиков событий задает параметр CategoryID коллекции SelectParameters в элементе управления SqlDataSource в зависимости от того, какая кнопка была нажата. Это дает пользователям возможность переключаться между двумя этими категориями.

  24. Сохраните изменения и нажмите CTRL+F5 для просмотра страницы в обозревателе.

  25. Нажмите кнопку Категория 2 и удостоверьтесь в том, что на странице отображаются новые сведения, но полного обновления страницы при этом не происходит.

    Bb398898.alert_note(ru-ru,VS.90).gifПримечание.

    Не закрывайте страницу.

    <%@ Page Language="VB" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <script runat="server">
    
        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 runat="server">
        <title>Products Display</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:ScriptManager ID="ScriptManager1" runat="server">
                </asp:ScriptManager>
                <asp:UpdatePanel ID="UpdatePanel1" runat="server" ChildrenAsTriggers="False" UpdateMode="Conditional">
                    <ContentTemplate>
                        <asp:Button ID="Category1Button" runat="server" Text="Category 1" OnClick="Category1Button_Click" />
                        <asp:Button ID="Category2Button" runat="server" OnClick="Category2Button_Click" Text="Category 2" />
                        <asp:DataList ID="DataList1" runat="server" DataKeyField="ProductID" DataSourceID="SqlDataSource1"
                            Width="231px">
                            <ItemTemplate>
                                ProductName:
                                <asp:Label ID="ProductNameLabel" runat="server" Text='<%# Eval("ProductName") %>'>
                                </asp:Label><br />
                                ProductID:
                                <asp:Label ID="ProductIDLabel" runat="server" Text='<%# Eval("ProductID") %>'></asp:Label><br />
                                <br />
                            </ItemTemplate>
                        </asp:DataList>
                        <asp:SqlDataSource ID="SqlDataSource1" runat="server" 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 runat="server">
    
        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 runat="server">
        <title>Products Display</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:ScriptManager ID="ScriptManager1" runat="server">
                </asp:ScriptManager>
                <asp:UpdatePanel ID="UpdatePanel1" runat="server" ChildrenAsTriggers="False" UpdateMode="Conditional">
                    <ContentTemplate>
                        <asp:Button ID="Category1Button" runat="server" Text="Category 1" OnClick="Category1Button_Click" />
                        <asp:Button ID="Category2Button" runat="server" OnClick="Category2Button_Click" Text="Category 2" />
                        <asp:DataList ID="DataList1" runat="server" DataKeyField="ProductID" DataSourceID="SqlDataSource1"
                            Width="231px">
                            <ItemTemplate>
                                ProductName:
                                <asp:Label ID="ProductNameLabel" runat="server" Text='<%# Eval("ProductName") %>'>
                                </asp:Label><br />
                                ProductID:
                                <asp:Label ID="ProductIDLabel" runat="server" Text='<%# Eval("ProductID") %>'></asp:Label><br />
                                <br />
                            </ItemTemplate>
                        </asp:DataList>
                        <asp:SqlDataSource ID="SqlDataSource1" runat="server" 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>
    

Вызов веб-службы для извлечения данных

Теперь следует вызвать веб-службу, используя созданный ранее файл JavaScript. Код JavaScript code использует возвращенные данные для заполнения элементов DOM в элементе управления UpdatePanel. Серверный код на странице сохраняет данные, полученные от веб-службы, и добавляет эти данные в состояние просмотра страницы. Это позволяет сохранить данные при последующей асинхронной обратной передаче.

Использование веб-службы для получения количества товара

  1. Переключитесь в режим конструктора на странице.

  2. Выберите элемент управления DataList и в панели Задачи DataList выберите Редактирование шаблонов.

  3. Добавьте к шаблону элемента элемент управления TextBox и элемент управления Button.

    Поместите новые элементы управления под существующим текстом и подписями шаблона.

  4. Выберите кнопку и в окне "Свойства" задайте для ее свойства Text значение Получить количество через веб-службу.

    Шаблон элемента для элемента управления DataList должен выглядеть приблизительно так.

    Урок UpdatePanel

  5. Выберите элемент управления DataList, после чего на вкладке События в окне "Свойства" дважды щелкните событие ItemDataBound.

  6. Добавьте следующий код:

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

    Этот код задает значения свойств каждого из объектов DataListItem следующим образом:

    • Свойство OnClientClick кнопки вызывает функцию JavaScript, которая, в свою очередь, обращается к веб-службе.

    • Значение текстового поля задается в том случае, если следящее свойство ProductInfo содержит ключ идентификатора товара. Свойство ProductInfo будет определено на следующем шаге данной процедуры.

  7. Добавьте на страницу свойство ProductInfo.

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

    Это свойство является объектом SortedList, отслеживающим данные, добавленные на страницу из веб-службы. При первой отрисовке страницы список будет пуст. При последующей асинхронной обратной передаче в список могут добавляться элементы.

  8. Добавьте следующий обработчик событий Page_Load:

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

    Этот код проверяет, является ли запрос асинхронной обработкой. Если это так, то все элементы данных, добавленные веб-службой, добавляются в свойство ProductInfo. Это позволяет отслеживать их в состоянии просмотра и отображать их в панели UpdatePanel при последующих частичных обновлениях страницы. Если элементы данных не отслуживаются в состоянии просмотра, то они не сохраняются при последующей асинхронной обратной передаче.

  9. Перейдите в режим конструктора.

  10. Выберите элемент управления ScriptManager.

  11. В окне "Свойства" выберите свойство Services и нажмите кнопку с многоточием ("…"), чтобы открыть диалоговое окно Редактор коллекции ServiceReference.

  12. Нажмите кнопку ОК, чтобы добавить ссылку на службу.

  13. Для свойства Path ссылки на службу задайте значение "ProductQueryService.asmx" — это веб-служба, созданная ранее.

    Добавление ссылки на службу приводит к тому, что элемент управления ScriptManager создает клиентские классы прокси, чтобы веб-службу можно было вызывать с использованием JavaScript.

    Урок UpdatePanel

  14. Нажмите кнопку ОК, чтобы закрыть диалоговое окно Редактор коллекции ServiceReference.

  15. Выберите элемент управления ScriptManager, после чего в окне "Свойства" выберите свойство Scripts и нажмите кнопку с многоточием ("…"), чтобы открыть диалоговое окно Редактор коллекции ScriptReference.

  16. Нажмите кнопку Добавить, чтобы добавить ссылку на сценарий.

  17. Задайте для свойства Path ссылки на сценарий значение "ProductQueryScript.js" — это файл JavaScript, созданный ранее.

    Добавление ссылки на сценарий приводит к тому, что элемент управления ScriptManager вставляет сценарий после того, как загрузится Microsoft AJAX (библиотека).

    Урок UpdatePanel

  18. Нажмите кнопку ОК, чтобы закрыть диалоговое окно Редактор коллекции ScriptReference.

  19. Сохраните изменения и нажмите CTRL+F5 для просмотра страницы в обозревателе.

    На странице будут отображены товары из базы данных "Northwind", код категории которых равен 1. Текстовые поля рядом с товарами будут пустыми, поскольку вызовы веб-службы не выполнялись.

    <%@ Page Language="VB" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <script runat="server">
    
        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 runat="server">
        <title>Products Display</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:ScriptManager ID="ScriptManager1" runat="server">
                    <Services>
                        <asp:ServiceReference Path="ProductQueryService.asmx" />
                    </Services>
                    <Scripts>
                        <asp:ScriptReference Path="ProductQueryScript.js" />
                    </Scripts>
                </asp:ScriptManager>
                <asp:UpdatePanel ID="UpdatePanel1" runat="server" ChildrenAsTriggers="False" UpdateMode="Conditional">
                    <ContentTemplate>
                        <asp:Button ID="Category1Button" runat="server" Text="Category 1" OnClick="Category1Button_Click" />
                        <asp:Button ID="Category2Button" runat="server" OnClick="Category2Button_Click" Text="Category 2" />
                        <asp:DataList ID="DataList1" runat="server" DataKeyField="ProductID" DataSourceID="SqlDataSource1"
                            Width="400px" OnItemDataBound="DataList1_ItemDataBound">
                            <ItemTemplate>
                                ProductName:
                                <asp:Label ID="ProductNameLabel" runat="server" Text='<%# Eval("ProductName") %>'>
                                </asp:Label><br />
                                ProductID:
                                <asp:Label ID="ProductIDLabel" runat="server" Text='<%# Eval("ProductID") %>'></asp:Label><br />
                                <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
                                <asp:Button ID="Button1" runat="server" Text="Get Quantity from Web Service" /><br />
                            </ItemTemplate>
                        </asp:DataList>
                        <asp:SqlDataSource ID="SqlDataSource1" runat="server" 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 runat="server">
    
        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 runat="server">
        <title>Products Display</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:ScriptManager ID="ScriptManager1" runat="server">
                    <Services>
                        <asp:ServiceReference Path="ProductQueryService.asmx" />
                    </Services>
                    <Scripts>
                        <asp:ScriptReference Path="ProductQueryScript.js" />
                    </Scripts>
                </asp:ScriptManager>
                <asp:UpdatePanel ID="UpdatePanel1" runat="server" ChildrenAsTriggers="False" UpdateMode="Conditional">
                    <ContentTemplate>
                        <asp:Button ID="Category1Button" runat="server" Text="Category 1" OnClick="Category1Button_Click" />
                        <asp:Button ID="Category2Button" runat="server" OnClick="Category2Button_Click" Text="Category 2" />
                        <asp:DataList ID="DataList1" runat="server" DataKeyField="ProductID" DataSourceID="SqlDataSource1"
                            Width="400px" OnItemDataBound="DataList1_ItemDataBound">
                            <ItemTemplate>
                                ProductName:
                                <asp:Label ID="ProductNameLabel" runat="server" Text='<%# Eval("ProductName") %>'>
                                </asp:Label><br />
                                ProductID:
                                <asp:Label ID="ProductIDLabel" runat="server" Text='<%# Eval("ProductID") %>'></asp:Label><br />
                                <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
                                <asp:Button ID="Button1" runat="server" Text="Get Quantity from Web Service" /><br />
                            </ItemTemplate>
                        </asp:DataList>
                        <asp:SqlDataSource ID="SqlDataSource1" runat="server" 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>
    

Проверка сохранения данных при асинхронной обратной передаче

Теперь можно видеть, как данные, полученные от веб-службы, сохраняются при асинхронной обратной передаче.

Проверка сохранения данных, полученных от веб-службы, при асинхронной обратной передаче

  1. Если страница не запущена, нажмите клавиши CTRL+F5, чтобы запустить ее.

  2. Нажмите кнопку Получить количество через веб-службу для любого товара в списке, и подождите, когда в текстовом поле появится значение.

  3. Нажмите кнопку Категория 2.

  4. Нажмите кнопку Категория 1.

    Обратите внимание, что значение, возвращенное веб-службой ранее, отображается даже после асинхронной обратной передачи.

Итог

В этом руководстве был приведен пример использования элемента управления UpdatePanel вместе с веб--службой, вызываемой из кода JavaScript в обозревателе. Веб-служба возвращает данные, отображаемые внутри элемента управления UpdatePanel.

Результаты вызова веб-службы из клиентского сценария и заполнения элементов DOM полученными данными будут одинаковыми вне зависимости от использования элементов управления UpdatePanel. Когда на странице выполняется обратная отправка или происходит асинхронная обратная передача, данные, отображавшиеся ранее при использовании клиентского сценария, будут утеряны. Чтобы избежать этой проблемы, можно использовать серверный код, сохраняющий данные путем внесения их в состав состояния просмотра. Это позволяет сохранять данные при асинхронной обратной передаче. Если данные, полученные от веб-службы, отображаются в элементах DOM, расположенных за пределами элементов управления UpdatePanel, и сохранять данные при асинхронной обратной передаче не требуется, то серверный код сохранения использовать необязательно.

Поскольку кнопка, инициирующая вызов веб-службы, находится внутри элемента управления UpdatePanel, для свойства ChildrenAsTriggers задается значение false. Другие элементы управления обратной передачи внутри панели определяются в качестве триггеров панели.

См. также

Основные понятия

Предоставление доступа к веб-службам в клиентском сценарии

Вызов веб-служб из клиентского сценария