.NET TIPS

[ASP.NET AJAX]AutoCompleteコントロールでGoogleサジェスト風なオートコンプリート機能を実装するには?[2.0のみ、C#、VB]

山田 祥寛
2007/03/15

 Googleマップと並んで、Ajax技術の適用例として挙げられることの多いアプリケーションとして、Googleサジェストを忘れることはできない。Googleサジェストはテキストボックスに入力された文字列から検索キーワードを推測して、候補一覧をポップアップ表示する、一種のオートコンプリート機能を提供するものだ。Googleマップのような見掛けの派手さはないものの、より汎用的にさまざまなアプリケーションに適用できるという意味では、Ajax技術の有効な適用例の1つといえるだろう。

 このGoogleサジェストによく似た機能を提供するのが、AutoCompleteコントロール(AutoCompleteExtender)。このコントロールは、ASP.NET AJAX Control Toolkit(以降、Control Toolkit)で提供されるコントロールの1つで、標準のテキストボックスを機能拡張して、オートコンプリート機能付きテキストボックスを生成する。

 本稿では、このAutoCompleteコントロールを利用して、サーバ側であらかじめ用意したキーワード情報を基に、動的に入力候補リストをポップアップ表示するアプリケーションを作成してみよう。以下がその実行例だ。

テキストボックスに「au」の2文字を入力
ポップアップ表示から項目を選択
本稿で作成するサンプル・アプリケーションの実行結果
テキストボックスに入力された文字列に応じて候補リストをポップアップ表示。リスト上で選択された項目をテキストボックスにフィードバックする。

 なお、本サンプルを動作させるに当たっては、「TIPS:[ASP.NET AJAX]ASP.NET AJAX Control Toolkitを利用するには?」で紹介した手順に従って、Control Toolkitを利用可能な状態にしておく必要がある。

1. オートコンプリート機能動作のためのデータソースを用意する

 まずは、入力候補リストを作成する基となるデータソースとして、以下のようなIndexListテーブルをデータベース上に作成しておこう。

フィールド名 データ型 概要
item VARCHAR(100) 表示項目(主キー)
IndexListテーブルのフィールド・レイアウト

 IndexListテーブルは、リスト上に表示する項目のみを定義したごくシンプルなテーブルだ。オートコンプリート機能を実際に確認できるよう、入力候補となる適当な項目をあらかじめセットしておくこと。

2. 新規のXML Webサービス・クラスを定義する

 AutoCompleteコントロールを利用するには、エンド・ユーザーが実際に入力した文字列をキーに入力候補を検索し、これを文字列配列の形式で返すXML Webサービス・クラスを用意しておく必要がある。

 以下に具体的なASP.NET Webサービス(.asmxファイル)のコードを示す。

<%@ WebService Language="C#" Class="AutoComplete" %>

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;
using System.Web.Services.Protocols;

[WebService(Namespace="http://tempuri.org/")]
[WebServiceBinding(ConformsTo=WsiProfiles.BasicProfile1_1)]
[ScriptService()]
public class AutoComplete : System.Web.Services.WebService {

  [WebMethod()]
  public String[] GetCompletionList(String prefixText, int count) {

    List<String> list = new List<String>();

    ConnectionStringSettings setting =
      ConfigurationManager.ConnectionStrings["MyDB"];
    DbProviderFactory factory =
      DbProviderFactories.GetFactory(setting.ProviderName);

    using(DbConnection db = factory.CreateConnection()) {

      db.ConnectionString = setting.ConnectionString;
      DbCommand comm = factory.CreateCommand();

      // パラメータprefixTextをキーに、
      // IndexListテーブルのitemフィールドを前方一致検索
      // (取得レコード数はパラメータcountで指定された件数で制限)
      comm.CommandText =
        String.Format("SELECT TOP {0} item FROM IndexList WHERE item LIKE @item", count);
      comm.Connection = db;
      DbParameter param = factory.CreateParameter();
      param.ParameterName = "@item";
      param.Value = prefixText + "%";
      comm.Parameters.Add(param);
      db.Open();

      // 取得した結果セットの内容を可変配列listに順番に追加
      DbDataReader reader = comm.ExecuteReader();
      while (reader.Read()) {
        list.Add(reader.GetString(0));
      }
    }
    return list.ToArray();
  }
}
<%@ WebService Language="VB" Class="AutoComplete" %>

Imports System.Collections.Generic
Imports System.Data
Imports System.Data.Common
Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.Web.Script.Services

<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<ScriptService()> _
Public Class AutoComplete
    Inherits System.Web.Services.WebService

    <WebMethod()> _
    Public Function GetCompletionList(ByVal prefixText As String, ByVal count As Integer) As String()

      Dim list As New List(Of String)

      Dim setting As ConnectionStringSettings = _
        ConfigurationManager.ConnectionStrings("MyDB")
      Dim factory As DbProviderFactory = _
        DbProviderFactories.GetFactory(setting.ProviderName)

      Using db As DbConnection = factory.CreateConnection()

        db.ConnectionString = setting.ConnectionString
        Dim comm As DbCommand = factory.CreateCommand()

        ' パラメータprefixTextをキーに、
        ' IndexListテーブルのitemフィールドを前方一致検索
        ' (取得レコード数はパラメータcountで指定された件数で制限)
        comm.CommandText = _
          String.Format("SELECT TOP {0} item FROM IndexList WHERE item LIKE @item", count)
        comm.Connection = db
        Dim param As DbParameter = factory.CreateParameter()
        param.ParameterName = "@item"
        param.Value = prefixText & "%"
        comm.Parameters.Add(param)
        db.Open()

        ' 取得した結果セットの内容を可変配列listに順番に追加
        Dim reader As DbDataReader = comm.ExecuteReader()
        Do While reader.Read()
          list.Add(reader.GetString(0))
        Loop
      End Using
      Return list.ToArray()
    End Function
End Class
入力候補リストを生成するためのXML Webサービス・クラス(AutoComplete.asmx)(上:C#版、下:VB版)

 サンプル・アプリケーションの大まかな流れについては、コード内のコメントを参照していただくとして、ここで注目していただきたいのは、以下の2点だ(なお、ここではXML Webサービス・クラスそのものの記法については割愛する。詳細については、「ASP.NETを使用したXML Webサービス」などを参照していただきたい)。

(1)XML Webサービス・クラスにはScriptService属性を付与する

 ScriptService属性(System.Web.Script.Services名前空間)は、該当のXML Webサービス・クラスがクライアント側スクリプトから呼び出し可能であるかどうかを表すものだ。

 AutoCompleteコントロールは(ほかの多くのExtender系のコントロールと同様に)内部的に自動生成したJavaScript経由でサーバ側のXML Webサービスと非同期通信を行うので、通信先となるXML Webサービス・クラスでは必ずScriptService属性を付与する必要がある。

(2)サービス・メソッドのパラメータ名、戻り値の型は固定

 AutoCompleteコントロールにおいて、サービス・メソッドの名前は自由に決めることができるが(ここではGetCompletionList)、戻り値のデータ型、および、パラメータの名前/データ型は完全に固定であり、アプリケーション開発者が変更することはできない。

 つまり、いかなる場合にもサービス・メソッドは以下のシグニチャに従う必要がある。C#/Visual Basic(VB)いずれを利用しているかにかかわらず、パラメータの名前は大文字/小文字まで厳密に区別されるので、注意してほしい。

[WebMethod()]
public String[] <メソッド名>(String prefixText, int count)
<WebMethod()> _
Public Function <メソッド名>(ByVal prefixText As String, ByVal count As Integer) As String()
AutoCompleteコントロールから呼び出されるサービス・メソッドのシグニチャ(上:C#、下:VB)

 サービス・メソッドがパラメータを介して受け取るのは、テキストボックスに実際に入力されたテキスト(prefixTextパラメータ)、入力候補リストに表示される最大項目数(countパラメータ)だ。ここでは、受け取ったパラメータ情報に基づいて、(例えば)以下のようなSQL命令を生成しているわけだ(パラメータのprefixTextが「au」、countが「10」の場合)。

SELECT TOP 10 item FROM IndexList WHERE item LIKE 'au%'

 なお、countパラメータには、後述するAutoCompleteコントロールのCompletionSetCountプロパティの値が引き渡される。このプロパティはあくまでサービス・メソッドに引き渡すパラメータを表すのみで、AutoCompleteコントロール側で項目の表示数を制御しているわけではない点に注意してほしい(つまり、サービス・メソッド側で項目の取得数を制限しない場合、合致したすべての項目がリスト表示されてしまう)。

3. 新規のWebフォームを作成する

 新規のWebフォーム(AutoComplete.aspx)を作成したら、フォーム・デザイナから以下の画面の要領でサーバ・コントロールを配置する。また、それぞれのコントロールに対しては、表の内容でプロパティ値を設定しておこう。

Webフォーム(AutoComplete.aspx)のレイアウト
新規に作成したWebフォームに対して、AutoCompleteコントロールを配置する。
コントロール プロパティ 設定値
ScriptManager(IDは「manager」)
TextBox(IDは「txtItem」) Columns 30
AutoCompleteExtender(IDは「comp」) CompletionSetCount 10
MinimumPrefixLength 2
ServiceMethod GetCompletionList
ServicePath AutoComplete.asmx
TargetControlID txtItem

 AutoCompleteコントロールのTargetControlIDプロパティは、オートコンプリート機能を付与するTextBoxコントロールを指定するものだ。これによって、TextBoxコントロール「txtItem」にAutoCompleteコントロールの機能が追加されたことになるわけだ。

 なお、AutoCompleteコントロールのそのほかのプロパティを設定する場合、(AutoCompleteコントロールではなく)関連付けたTextBoxコントロールのプロパティとして設定する必要がある点に注意してほしい。本稿の場合であれば、TextBoxコントロールのプロパティ・ウィンドウに「comp(AutoCompleteExtender)」という項目が追加されているので、この項目の配下から個々の値を設定する。

 AutoCompleteコントロールで利用可能な主なプロパティは以下のとおり。

プロパティ名 概要
TargetControlID 関連付けるTextBoxコントロールのID値
ServicePath 値リスト取得に使用するXML Webサービス(.asmxファイル)のパス
ServiceMethod 値リスト取得に使用するサービス・メソッドの名前
MinimumPrefixLength オートコンプリート動作のために必要な最小入力文字数
CompletionInterval 入力からオートコンプリート機能が動作するまでの時間(ミリ秒)
EnableCaching クライアントサイド・キャッシュを有効にするか
CompletionSetCount サービス・メソッドから取得する最大項目数
AutoCompleteコントロールの主なプロパティ

 多くのプロパティが用意されているが、最低限、設定が必要なのは値リストを取得するためのサービス・メソッドを特定するServicePath/ServiceMethodプロパティ、オートコンプリート機能が動作するための最低限の入力文字数を表すMinimumPrefixLengthプロパティだ。

 MinimumPrefixLengthプロパティのデフォルト値は1であるが、ヒットする項目数があまりに多い場合には、候補リストを表示しても無駄になる可能性が高い(上位何件かに目的の項目が含まれていない可能性が高い)。不要な通信を減らすためにも、ある程度適切な結果が絞り込まれるまで機能が動作しないよう、適切な値を指定することをお勧めする。

 ちなみにここでは、テキストボックスに2文字以上の文字列が入力されたタイミングでオートコンプリート機能が動作し、最大10個の候補リストがポップアップ表示されるというわけだ。

 なお参考までに、ここまでにVisual Studio 2005で自動生成されたコードを引用しておく。プロパティ・ウィンドウ上ではTextBoxコントロール配下のプロパティとして設定したServicePath/ServiceMethodプロパティなども、コード上はAutoCompleteコントロールの属性として記述されていることが確認できるはずだ。

<%--Control Toolkitを使用する場合には先頭にScriptManagerの配置は必須--%>
<asp:ScriptManager ID="manager" runat="server">
  </asp:ScriptManager>
<asp:TextBox ID="txtItem" runat="server" Columns="30"></asp:TextBox>
<%--AutoCompleteコントロールの諸設定--%>
<ajaxToolkit:AutoCompleteExtender ID="comp" runat="server"
  MinimumPrefixLength="2" ServiceMethod="GetCompletionList"
  ServicePath="AutoComplete.asmx" TargetControlID="txtItem"
  CompletionSetCount="5">
  </ajaxToolkit:AutoCompleteExtender>
AutoComplete.aspxのソース・コード(抜粋)
一連のレイアウト編集を行った後、Visual Studio 2005によって自動生成されたコードを引用したもの。なお、<%--〜--%>は筆者によるコメント。

 以上を理解したら、さっそく作成したサンプル・プログラムを実行してみよう。冒頭の画面のように、テキストボックスに文字を入力すると、それに合致したIndexListテーブル上の項目群がポップアップ表示されることが確認できるはずだ。End of Article

利用可能バージョン:.NET Framework 2.0のみ
カテゴリ:Webフォーム 処理対象:ASP.NET AJAX
使用ライブラリ:AutoCompleteコントロール
使用ライブラリ:AutoCompleteコントロール
関連TIPS:[ASP.NET AJAX]ASP.NET AJAX Control Toolkitを利用するには?

この記事と関連性の高い別の.NET TIPS
[ASP.NET AJAX]DynamicPopulateコントロールでXML Webサービスを非同期に呼び出すには?
[ASP.NET AJAX]ダイナミック・コンテキスト機能でポップアップ・コントロールの内容を動的に生成するには?
オートコンプリート機能で独自の補完候補を使用するには?
[ASP.NET AJAX]NumericUpDownコントロールでアップダウン・ボタンを生成するには?
[ASP.NET AJAX]クライアントサイド・スクリプトからXML Webサービスを非同期呼び出しするには?(サーバサイド編)
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間