[ASP.net/Ajax] TextBox輸入文字自動完成(非WebService和使用WebService寫法整理)
如果想在TextBox上輸入文字,即時出現一個Layer文字列表,類似Google搜尋那樣
	
一般的做法是使用WebService吧
1.先看WebService
以個人測試Web site範例,我是開一個WebService資料夾在根目錄下,然後加入一個WebService.asmx
	
同時Visual Studio也會產生一份WebService.cs檔在App_Code資料夾內
WebService.cs內的程式碼:
using System.Collections;
using System.Data;
using System.Data.SqlClient;
[System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService {
    [System.Web.Services.WebMethodAttribute(), System.Web.Script.Services.ScriptMethodAttribute()]
    //方法不可宣告static
    public string[] GetCompletionList(string prefixText, int count)
    {
        //資料庫連線字串
        string connStr = @"Data Source=.\SQLEXPRESS;AttachDbFilename="
                     + System.Web.HttpContext.Current.Server.MapPath("~/App_Data/NorthwindChinese.mdf") + ";Integrated Security=True;User Instance=True";
        ArrayList array = new ArrayList();//儲存撈出來的字串集合
        using (SqlConnection conn = new SqlConnection(connStr))
        {
            DataSet ds = new DataSet();
            string selectStr = @"SELECT Top (" + count + ") CompanyName FROM Customers Where CompanyName Like '" + prefixText + "%' Order by CustomerID ASC";
            SqlDataAdapter da = new SqlDataAdapter(selectStr, conn);
            conn.Open();
            da.Fill(ds);
            foreach (DataRow dr in ds.Tables[0].Rows)
            {
                array.Add(dr["CompanyName"].ToString());
            }
        }
        return (string[])array.ToArray(typeof(string));
    } 
    
}
接著新增一個UseWebService.aspx檔案在根目錄
aspx程式碼
<%@ Page Language="C#" AutoEventWireup="true"  %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<html>
<head >
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server" />
    <asp:TextBox ID="TextBox1" runat="server" />
    <asp:AutoCompleteExtender
           ID="AutoCompleteExtender1"
           runat="server"
           MinimumPrefixLength="1"
           TargetControlID="TextBox1"
           ServiceMethod="GetCompletionList"
           ServicePath="WebService/WebService.asmx"
           CompletionSetCount="15" 
    />
    <!--AutoCompleteExtender成員說明
    MinimumPrefixLength:最少輸入幾個字就呼叫Method
    TargetControlID:哪個TextBox要有自動完成功能
    ServiceMethod:呼叫的Method名
    ServicePath:WebService路徑
    CompletionSetCount:要列出幾筆資料
    -->
    </form>
</body>
</html>
結束,因為Code-Behind沒有要寫程式,所以我把UseWebService.aspx.cs宰了
2.接著再看不使用WebService的做法
先在App_Code裡新增一個AutoComplete_WebPage.cs類別
AutoComplete_WebPage.cs的程式碼
using System.Data;
using System.Data.SqlClient;
using System.Collections;
//類別繼承System.Web.UI.Page目的是為了讓其他aspx.cs可以再繼承下來使用
public class AutoComplete_WebPage :System.Web.UI.Page
{
    [System.Web.Services.WebMethodAttribute(), System.Web.Script.Services.ScriptMethodAttribute()]
    //一定要宣告成static才有效果
    public static string[] GetCompletionList(string prefixText, int count)
    {
        //連線字串
        string connStr = @"Data Source=.\SQLEXPRESS;AttachDbFilename="
                     + System.Web.HttpContext.Current.Server.MapPath("~/App_Data/NorthwindChinese.mdf") + ";Integrated Security=True;User Instance=True";
        ArrayList array = new ArrayList();//儲存撈出來的字串集合
        using (SqlConnection conn = new SqlConnection(connStr))
        {
            DataSet ds = new DataSet();
            string selectStr = @"SELECT Top (" + count + ") CompanyName FROM Customers Where CompanyName Like '" + prefixText + "%' Order by CustomerID ASC";
            SqlDataAdapter da = new SqlDataAdapter(selectStr, conn);
            conn.Open();
            da.Fill(ds);
            foreach (DataRow dr in ds.Tables[0].Rows)
            {
                array.Add(dr["CompanyName"].ToString());
            }
        }
        return (string[])array.ToArray(typeof(string));
    } 
}
接著在網站根目錄下新增一個NoWebService.aspx
NoWebService.aspx程式碼
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="NoWebService.aspx.cs" Inherits="NoWebService" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<html>
<head runat="server">
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server" />
    <asp:TextBox ID="TextBox1" runat="server" />
    <asp:AutoCompleteExtender
           ID="AutoCompleteExtender1"
           runat="server"
           TargetControlID="TextBox1"
           MinimumPrefixLength="1"
           ServiceMethod="GetCompletionList"
           CompletionSetCount="15" 
    />
    </form>
</body>
</html>
NoWebService.aspx.cs程式碼
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
//繼承AutoComplete_WebPage類別
public partial class NoWebService : AutoComplete_WebPage
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }
}
3.最後分別把UseWebService.aspx或NoWebService.aspx執行起來,效果一樣
(註:Firefox 更新到4.x版以上可以支援ASP.net Ajax的自動完成)
整理一下兩者寫法差異
| 新增項目 | App_Code/cs檔類別 | App_Code/cs檔方法 | 網頁程式 | |
|---|---|---|---|---|
| 使用WebService | WebService.asmx、WebService.cs檔 | 
				類別加[System.Web.Script.Services.ScriptService]屬性, 並繼承System.Web.Services.WebService  | 
			方法不可宣告static否則無效 | 
				aspx頁面的AutoCompleteExtender擴充項 須指定ServicePath  | 
		
| 不使用WebService | 加入一個類別AutoComplete_WebPage.cs | 類別繼承System.Web.UI.Page | 一定要宣告成static才有效果 | aspx.cs須繼承自訂類別 | 
不使用WebService做法的原理:
每支aspx程式要有自己的public static Method(服務方法),若寫在MasterPage或WebUserControl的話,ServiceMethod會抓不到,所以只好用繼承的方式,讓有需要做自動完成功能的aspx程式繼承自訂類別,而該自訂類別就是實現自動完成功能的System.Web.UI.Page子類別
====================
2011/9/2 眼尖的讀者可以發現以上的SQL查詢會有SQL Injection危險,所以以上 SqlDataAdapter 的查詢語法最好改成以下:
string selectStr = @"SELECT Top (" + count + ") CompanyName FROM Customers Where CompanyName Like @prefixText + '%' Order by CustomerID ASC";
	SqlDataAdapter da = new SqlDataAdapter(selectStr, conn);
	da.SelectCommand.Parameters.AddWithValue("@prefixText", prefixText);
再附上黑暗執行緒網友的jQuery AutoComplete懶人包文章
MSDN相關討論:http://social.msdn.microsoft.com/Forums/zh-TW/236/thread/0ffc9ef8-3577-4f2c-9867-aae692235717
2011/10/19 追加說明
如果是在MasterPage或是WebControl做自動完成的話,建議採用WebService的方式,才能成功。