UpdatePanel コントロールと Web サービスの使用

更新 : 2007 年 11 月

UpdatePanel コントロールを使用すると、ASP.NET Web ページで部分ページ レンダリングを簡単に実行できます。これは、ASP.NET の AJAX 機能により、非同期ポストバックの要求および更新が自動的に管理されるためです。また AJAX 機能により、ブラウザで ECMAScript (JavaScript) を使用して ASP.NET Web サービスを呼び出すことができます。クライアント スクリプトを使用して Web サービスを呼び出すことの利点の 1 つは、Web サービス要求からの応答を待つ間、ブラウザがブロックされないことです。ユーザーは、Web サービスにより要求が完全に処理されるのを待たずに、作業を続けて行うことができます。

このチュートリアルでは、UpdatePanel コントロールを使用して Web サービスを使用する方法を説明します。JavaScript 関数で Web サービスを呼び出してデータを取得し、UpdatePanel コントロール内の DOM 要素にその Web サービスから返されたデータを設定します。非同期ポストバックと非同期ポストバックの間、サーバー コードにより取得した Web サービス データを保存します。

このトピックを理解するには、UpdatePanel コントロールと Web サービスについて理解している必要があります。これらの詳細については、次のトピックを参照してください。

前提条件

この手順を各自の開発環境で実行するには、以下が必要です。

  • Microsoft Visual Studio 2005 または Visual Web Developer Express Edition。

  • AJAX 対応の ASP.NET Web サイト。

  • Northwind データベースへのアクセス権。また、NorthwindConnectionString という名前の接続文字列を Web.config ファイルで定義する必要があります。接続文字列を作成する方法の詳細については、「方法 : Web.config ファイルから接続文字列を読み取る」を参照してください。

Web サービスの作成

最初に、呼び出し可能な Web サービスを作成します。

製品の数量を返す Web サービスを作成するには

  1. AJAX 対応の ASP.NET Web サイトに、ProductQueryService.asmx という名前の新しい Web サービス ファイルを作成します。

    Web サービスを作成する方法の詳細については、「クライアント スクリプトからの Web サービスの呼び出し」を参照してください。

  2. Web サービス コードで、N:System.DataN:System.Data.SqlClientSystem.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;
    

    これらの名前空間に属する型を、作成する Web サービス メソッドで使用します。

  3. ProductQueryService クラスを Samples という名前の名前空間内に配置します。

  4. クラスに ScriptServiceAttribute 属性を追加します。

    この属性により、クライアント スクリプトから Web サービスを呼び出すことができます。

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

    コードは次のタスクを実行します。

    • NorthwindConnectionString という名前の接続文字列を使用する、新しい SqlConnection オブジェクトを作成します。

    • 指定した製品 ID の在庫の数を取得する SQL コマンドを含む、新しい SqlCommand オブジェクトを作成します。

    • ブラウザに送信する応答として使用される文字列に戻り値を設定します。

      Bb398898.alert_note(ja-jp,VS.90).gifメモ :

      このチュートリアルでは、Web メソッドにより意図的に遅延を発生させます。実際には、意図的に遅延を発生させることはありません。サーバー トラフィックや、処理に時間がかかる Web サービス コード (長時間実行されるデータベース クエリなど) によって遅延が発生します。

  6. 変更内容を保存し、Ctrl キーを押しながら F5 キーを押して、ブラウザでページを表示します。

  7. [GetProductQuantity] リンクをクリックして Web メソッドを呼び出します。

  8. [productID] ボックスに「6」と入力し、[Invoke] をクリックします。

    製品の数量が XML としてブラウザに返されます。Web サービスが意図したとおりに機能すると、このように数量が返されます。

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

Web サービスを呼び出す JavaScript コードの作成

この手順では、前の手順で作成した Web サービスを呼び出す JavaScript ファイルを作成します。

Web サービスを使用する JavaScript ファイルを作成するには

  1. ProductQueryScript.js という名前の新しい JScript ファイルを作成します。

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

    このスクリプトは、次のタスクを実行します。

    • Web サービス メソッドの GetProductQuantity を呼び出す GetQuantity という名前の関数を作成します。

    • Web サービス呼び出しが結果を返したときに呼び出される OnSucceeded という名前の関数を作成します。

データを表示する Web ページの作成

次に、UpdatePanel コントロールを含む Web ページを作成します。UpdatePanel コントロール内部のコントロールで、Northwind データベースから製品情報を取得して表示します。

製品を表示する Web ページを作成するには

  1. 新しい Web ページを作成し、デザイン ビューに切り替えます。

  2. ツールボックスの [AJAX Extensions] タブで、ScriptManager コントロールをダブルクリックしてページに追加します。

  3. ツールボックスで UpdatePanel コントロールをダブルクリックして、UpdatePanel コントロールをページに追加します。

    UpdatePanel のチュートリアル

  4. UpdatePanel コントロールの内部をクリックし、ツールボックスの [データ] タブで DataList コントロールをダブルクリックします。

  5. [DataList タスク] パネルの [データ ソースの選択] の一覧で [<新しいデータ ソース>] をクリックします。

    Bb398898.alert_note(ja-jp,VS.90).gifメモ :

    [DataList タスク] パネルが表示されない場合は、DataList コントロールを右クリックし、[スマート タグの表示] をクリックします。

    データ ソース構成ウィザードが表示されます。

  6. [データベース] をクリックし、既定の名前の SqlDataSource1 を受け入れ、[OK] をクリックします。

  7. [アプリケーションがデータベースへの接続に使用するデータ接続] の一覧で [NorthwindConnectionString] をクリックし、[次へ] をクリックします。

  8. [データベースからデータをどうやって取得しますか?][テーブルまたはビューから列を指定します] をクリックし、一覧から [Products] をクリックします。次に、[列] の一覧で [ProductID][ProductName] をクリックします。

  9. [Where] をクリックします。

    [WHERE 句の追加] ダイアログ ボックスが表示されます。

  10. [列] の一覧で [CategoryID] をクリックし、[ソース] の一覧で [なし] をクリックします。

  11. ダイアログ ボックスの [パラメータのプロパティ] セクションの [値] ボックスに、「1」を入力します。

  12. [追加] をクリックして、WHERE 句を SQL ステートメントに追加します。

  13. [OK] をクリックして、[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. 2 つの Button コントロールを、DataList コントロールの外側の UpdatePanel コントロールに追加します。

  19. 1 番目のボタンの ID プロパティを Category1Button に、Text プロパティを Category 1 にそれぞれ設定します。2 番目のボタンの ID プロパティを Category2Button に、Text プロパティを Category 2 にそれぞれ設定します。

    UpdatePanel のチュートリアル

  20. UpdatePanel コントロールを選択し、[プロパティ] ウィンドウで UpdateMode プロパティを Conditional に、ChildrenAsTriggers プロパティを false にそれぞれ設定します。

  21. [トリガ] ボックスで、省略記号ボタン ([…]) をクリックし、[UpdatePanel Trigger コレクション エディタ] ダイアログ ボックスで、非同期ポストバックのトリガとして各カテゴリのボタンを追加します。

    UpdatePanel のチュートリアル

  22. 1 番目のボタンの Click イベント ハンドラを Category1Button_Click に設定し、2 番目のボタンの Click イベント ハンドラを Category2Button_Click に設定します。

  23. ソース ビューに切り替えて、2 つのボタンに対し次のイベント ハンドラを作成します。

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

    このイベント ハンドラのコードでは、どのボタンが押されたかに基づき、SqlDataSource コントロールの SelectParameters コレクションの CategoryID パラメータが設定されます。これにより、ユーザーは 2 つのカテゴリを切り替えることができます。

  24. 変更内容を保存し、Ctrl キーを押しながら F5 キーを押して、ブラウザでページを表示します。

  25. Category 2 をクリックし、ページに新しい情報が表示され、ページ全体は更新されないことを確認します。

    Bb398898.alert_note(ja-jp,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>
    

Web サービスの呼び出しによるデータの取得

ここでは、前の手順で作成した JavaScript ファイルを使用して Web サービスを呼び出します。JavaScript コードで、返されたデータを使用して UpdatePanel コントロールの内部に DOM 要素を設定します。ページのサーバー コードで、Web サービスから読み込んだデータを保存し、そのデータをページのビューステートに追加します。これにより、後続の非同期ポストバックでもデータが保持されます。

製品の数量を返す Web サービスを使用するには

  1. ページで、デザイン ビューに切り替えます。

  2. DataList コントロールを選択し、[DataList タスク] パネルで [テンプレートの編集] をクリックします。

  3. TextBox コントロールおよび Button コントロールを項目テンプレートに追加します。

    新しいコントロールは、テンプレートの既存のテキストおよびラベルの下に追加します。

  4. ボタンを選択し、[プロパティ] ウィンドウで Text プロパティを Get Quantity from Web Service に設定します。

    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 関数が呼び出されます。この関数は Web サービスを呼び出します。

    • ProductInfo という名前の追跡プロパティに製品 ID のキーが含まれる場合、テキスト ボックスの値が設定されます。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; }
    }
    

    このプロパティは、Web サービスからページに追加されたデータを追跡する 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;
        }
    }
    

    このコードでは、要求が非同期ポストバックかどうかチェックされます。非同期ポストバックの場合、Web サービスにより追加されたデータ項目が ProductInfo プロパティに追加されます。これにより、データ項目がビューステートで追跡されるようになり、以降の部分ページ更新時にそれらのデータ項目が UpdatePanel に表示されるようになります。データ項目がビューステートで追跡されないと、それらのデータ項目は以降の非同期ポストバックでは保持されません。

  9. デザイン ビューに切り替えます。

  10. ScriptManager コントロールを選択します。

  11. [プロパティ] ウィンドウで、Services プロパティをクリックします。次に、省略記号 ([…]) ボタンをクリックして、[ServiceReference コレクション エディタ] ダイアログ ボックスを表示します。

  12. [追加] をクリックしてサービス参照を追加します。

  13. サービス参照の Path プロパティを ProductQueryService.asmx (前の手順で作成した Web サービス) に設定します。

    サービス参照を追加すると、ScriptManager コントロールによりクライアント プロキシ クラスが生成されます。これにより、JavaScript を使用して Web サービスを呼び出すことができます。

    UpdatePanel のチュートリアル

  14. [OK] をクリックして [ServiceReference コレクション エディタ] ダイアログ ボックスを閉じます。

  15. ScriptManager コントロールを選択し、[プロパティ] ウィンドウで Scripts プロパティを選択し、省略記号 [(…)] ボタンをクリックして [ScriptReference コレクション エディタ] ダイアログ ボックスを表示します。

  16. [追加] をクリックしてスクリプト参照を追加します。

  17. スクリプト参照の Path プロパティを ProductQueryScript.js (前の手順で作成した JavaScript ファイル) に設定します。

    スクリプト参照を追加すると、Microsoft AJAX Library が読み込まれた後、ScriptManager コントロールによりスクリプトが挿入されます。

    UpdatePanel のチュートリアル

  18. [OK] をクリックして [ScriptReference コレクション エディタ] ダイアログ ボックスを閉じます。

  19. 変更内容を保存し、Ctrl キーを押しながら F5 キーを押して、ブラウザでページを表示します。

    カテゴリ ID が 1 の製品が Northwind データベースから取得されてページに表示されます。Web サービスの呼び出しは行われていないため、各製品の隣のテキスト ボックスは空です。

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

非同期ポストバック時のデータ保持の確認

この時点で、Web サービスから取得したデータが非同期ポストバック時にどのように保持されているか確認できます。

非同期ポストバック時に Web サービス データが保持されていることを確認するには

  1. ページが実行されていない場合は、Ctrl キーを押しながら F5 キーを押してページを実行します。

  2. 一覧内の製品の Get Quantity from Web Service ボタンをクリックし、テキスト ボックスに値が表示されるまで待ちます。

  3. Category 2 ボタンをクリックします。

  4. Category 1 ボタンをクリックします。

    非同期ポストバックの後でも、Web サービスが最初に返した値が引き続き表示されていることに注意してください。

レビュー

このチュートリアルでは、UpdatePanel コントロールと、ブラウザで JavaScript コードから呼び出した Web サービスを使用する例を紹介しました。この Web サービスは、UpdatePanel コントロール内部に表示されるデータを返します。

クライアント スクリプトから Web サービスを呼び出した結果および返されたデータを使用して DOM 要素を設定した結果は、UpdatePanel コントロールがある場合もない場合も同じす。ページがポストバックを実行したとき、または非同期ポストバックが発生したとき、クライアント スクリプトを使用して表示されていた以前のデータは失われます。この問題を回避するには、サーバー コードを使用してデータをビューステートの一部にすることでそのデータを保持します。このようにすると、後続の非同期ポストバック時にデータが保持されます。Web サービスから取得したデータを UpdatePanel コントロールの外側の DOM 要素に表示し、非同期ポストバック時にそれらのデータを保持する必要がない場合は、それらのデータを保持するためのサーバー コードを用意する必要はありません。

Web サービス呼び出しをトリガするボタンは UpdatePanel コントロールの内部にあるので、ChildrenAsTriggers プロパティは false に設定します。パネル内部のその他のポストバック コントロールはパネルのトリガとして定義されます。

参照

概念

クライアント スクリプトへの Web サービスの公開

クライアント スクリプトからの Web サービスの呼び出し