65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Autocomplete Extender 实现类似 Google 的建议

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.36/5 (11投票s)

2008 年 6 月 24 日

CPOL

4分钟阅读

viewsIcon

111053

downloadIcon

2581

如何使用 autocomplete extender 提供联系人建议

引言

此示例演示了如何使用 ASP.NET AJAX Control Toolkit 中的 AutoCompleteExtender 控件,并在不修改它的情况下自定义其行为。

背景

我喜欢 Google 的建议功能,并曾想在我的任何项目中使用它。ASP.NET 的 AJAX Control Toolkit 有一个类似的控件(AutoCompleteExtender),它提供了完成此功能所需的基本项。我搜索了它的用法,找到了很多示例,但并不满意。它们都只使用此扩展器填充单个字段。

然后我想到一个主意,为什么不只用一个扩展器填写联系人详细信息,包括姓名、电子邮件地址和电话号码,而且不修改任何提供的功能,以便我们的代码可以用于新版本。下面是填写联系人表单后的效果。

AutoSuggest

Using the Code

让我们来看看 AutoCompleteExtender 是如何工作的。下面是工具包示例站点上对它的描述。

AutoComplete 是一个 ASP.NET AJAX 扩展器,可以附加到任何 TextBox 控件,并将该控件与弹出面板关联,以显示以 textbox 中键入的前缀开头的单词。

由 Web 服务提供的候选单词的 dropdown 位于 textbox 的左下方。

它说这个控件将从 Web 服务获取数据,并且可以附加到 TextBox 控件(它只能附加到一个控件)。当用户开始在该 TextBox 控件中键入时,它会从配置的 Web 服务获取建议列表。

所以我们需要两样东西:一个是我们的示例联系人页面,另一个是一个 Web 服务。这是我们的 Web 服务代码。

using System;
using System.Web;
using System.Collections;
using System.Collections.Generic;
using System.Web.Script;
using System.Web.Script.Serialization;
using System.Web.Script.Services;
using System.Web.Services;
using System.Web.Services.Protocols;
using AjaxControlToolkit;


/// <summary>
/// Summary description for SuggestionService
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService()]
public class SuggestionService : System.Web.Services.WebService {

    public SuggestionService () {

        //Uncomment the following line if using designed components 
        //InitializeComponent(); 
    }

    [WebMethod]
    [ScriptMethod()]
    public string[] GetContacts(string prefixText, int count, string contextKey) {
        List<string> items = new List<string>();
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        ContactManager manager = new ContactManager();
        List<contact> contacts = manager.GetContacts
				(int.Parse(contextKey), prefixText, count);
        foreach (Contact c in contacts)
        {
            items.Add(AutoCompleteExtender.CreateAutoCompleteItem
				(c.FullName, serializer.Serialize(c)));
        }

        return items.ToArray();
    }    
}

您会注意到服务和 Web 方法上的一些额外修饰。您必须用“ScriptService”属性修饰此服务,因为没有它,您将无法从客户端脚本访问它。

[ScriptService()]
public class SuggestionService : System.Web.Services.WebService {

我们的 webmethod 将返回 JSON 格式的 string 项列表,因此它也需要在其上添加 ScriptMethod 属性。

    [WebMethod]
    [ScriptMethod()]
    public string[] GetContacts(string prefixText, int count, string contextKey) {}

此外,您还注意到我以不同的方式返回了这些数据。我使用了 AutoCompleteExtender 来创建自己的条目,因为我想从 Web 服务返回一些额外数据,以便填充联系人表单上的所有相关字段。此功能仅在 AJAX Control Toolkit 的最新版本(1.0.20229.0)中可用。在此之前不可用。它提供键值对,如果您想为内部 ID 显示友好名称列表,这是一个非常有用的功能。CreateAutoCompleteItem 方法接受两个参数,第一个是要显示的文本,第二个是可以通过页面上的任何自定义脚本使用的值。

items.Add(AutoCompleteExtender.CreateAutoCompleteItem
			(c.FullName, serializer.Serialize(c)));

现在我还有另一个障碍需要克服,如何传递复杂的联系人数据。现在 JSON 来救援我了。我使用 JavaScriptSerializer 序列化了我的联系人对象。

到目前为止,我一直夸耀我的联系人对象有点复杂,下面是它的样子。下面是我的 ContactPhone 类。

/// <summary>
/// Summary description for Contact
/// </summary>
public class Contact
{
    protected int _contactId;
    public int ContactId
    {
        get { return _contactId; }
    }

    protected int _companyId;
    public int CompanyId
    {
        get { return _companyId; }
        set { _companyId = value; }
    }

    protected string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; }
    }

    protected string _lastName;
    public string LastName
    {
        get { return _lastName; }
        set { _lastName = value; }
    }

    public string FullName
    {
        get { return _firstName + ' ' + _lastName; }
    }

    protected string _email;
    public string Email
    {
        get { return _email; }
        set { _email = value; }
    }
    public int _homePhoneId;
    public int _workPhoneId;

    protected Phone _homePhone;

    public Phone HomePhone
    {
        get { return _homePhone; }
        set { _homePhone = value; }
    }
    protected Phone _workPhone;

    public Phone WorkPhone
    {
        get { return _workPhone; }
        set { _workPhone = value; }
    }


    public Contact() : this(0, 0, 0)
    {
    }

    public Contact(int id) : this(id, 0, 0)
    {
    }

    public Contact(int id, int homephone, int workphone)
    {
        _contactId = id;
        _homePhoneId = homephone;
        _workPhoneId = workphone;
    }
}

/// <summary>
/// Summary description for Phone
/// </summary>
public class Phone
{
    protected int _phoneId;
    public int PhoneId
    {
        get { return _phoneId; }
    }

    protected string _areaCode;
    public string AreaCode
    {
        get { return _areaCode; }
        set { _areaCode = value; }
    }

    protected string _prefix;
    public string Prefix
    {
        get { return _prefix; }
        set { _prefix = value; }
    }

    protected string _number;
    public string Number
    {
        get { return _number; }
        set { _number = value; }
    }

    protected string _extension;
    public string Extension
    {
        get { return _extension; }
        set { _extension = value; }
    }

    public Phone() : this(0)
    {
    }

    public Phone(int id)
    {
        _phoneId = id;
    }
}

现在我们需要处理我们的联系人页面。下面是它的基本 HTML。此联系人表单包含姓、名、电子邮件地址和电话号码字段。每个电话号码又包含前缀、区号、号码和分机字段。

<div style="border: 1px solid rgb(204, 204, 204); padding: 10px; width: 400px;">
    <table cellspacing="0" cellpadding="0" border="0">
        <tbody><tr>
            <td style="width: 100px; text-align: right;">First Name:</td>
            <td><asp:textbox runat="server" id="txtFirstName" /></td>
        </tr>
        <tr>
            <td style="width: 100px; text-align: right;">Last Name:</td>
            <td><asp:textbox runat="server" id="txtLastName" /></td>
        </tr>
        <tr>
            <td style="width: 100px; text-align: right;">Home Phone:</td>
            <td>
                <table cellspacing="0" cellpadding="0" border="0">
                    <tbody><tr>
                        <td><asp:textbox columns="3" 
				runat="server" id="txtHPAreaCode" /></td>
                        <td>-<asp:textbox columns="3" 
				runat="server" id="txtHPPrefix" /></td>
                        <td>-<asp:textbox columns="3" 
				runat="server" id="txtHPNumber" /></td>
                    </tr>
                </tbody></table>
            </td>
        </tr>
        <tr>
            <td style="width: 100px; text-align: right;">Work Phone:</td>
            <td>
                <table cellspacing="0" cellpadding="0" border="0">
                    <tbody><tr>
                        <td><asp:textbox columns="3" 
				runat="server" id="txtWPAreaCode" /></td>
                        <td>-<asp:textbox columns="3" 
				runat="server" id="txtWPPrefix" /></td>
                        <td>-<asp:textbox columns="3" 
				runat="server" id="txtWPNumber" /></td>
                        <td> x </td>
                        <td><asp:textbox columns="3" 
				runat="server" id="txtWPExtension" /></td>
                    </tr>
                </tbody></table>
            </td>
        </tr>
        <tr>
            <td style="width: 100px; text-align: right;">Email Address :</td>
            <td><asp:textbox runat="server" id="txtEmail" /></td>
        </tr>
    </tbody></table>
</div>

要在此页面上使用 AutoCompleteExtender,请先放置 ScriptManager 控件,然后放置 AutoCompleteExtender 控件,并将其 TargetControlId 设置为姓氏 TextBox 控件。这将为姓氏 TextBox 控件添加一些额外的属性。这些属性与其附加的扩展器有关,您可以在 AutoCompleteExtender 示例页面上找到它们的描述。我们必须设置其中一些属性来激活它的工作。

首先指定 ServicePath 并将其设置为我们刚刚创建的 Web 服务,然后设置 ServiceMethod,它将返回建议列表。这将是我们服务中的 Web 方法。我们也可以使用 context key,这有助于我们过滤建议。在我们的例子中,我使用它来传递当前公司信息,以便我可以返回特定公司的联系人。

这样就完成了我们的基本设置。如果您现在测试此页面,在姓氏字段中键入两个字母后,您将看到一个建议列表,并且当您从该列表中选择任何项时,只有姓氏字段会被设置为选定的姓名。所有其他字段将保持空白。

现在我们需要添加我们的魔术代码,它将使我们能够实现我们的目标。

<script type="text/javascript">
    function OnContactSelected(source, eventArgs)
    {
        var results = eval('('  + eventArgs.get_value() + ')');
        $get('txtFirstName').value = results.FirstName;
        $get('txtLastName').value = results.LastName;
        if (results.HomePhone.AreaCode != null)
            $get('txtHPAreaCode').value = results.HomePhone.AreaCode;
        if (results.HomePhone.Prefix != null)
            $get('txtHPPrefix').value = results.HomePhone.Prefix;
        if (results.HomePhone.Number != null)
            $get('txtHPNumber').value = results.HomePhone.Number;
        if (results.WorkPhone.AreaCode != null)
            $get('txtWPAreaCode').value = results.WorkPhone.AreaCode;
        if (results.WorkPhone.Prefix != null)
            $get('txtWPPrefix').value = results.WorkPhone.Prefix;
        if (results.WorkPhone.Number != null)
            $get('txtWPNumber').value = results.WorkPhone.Number;
        if (results.WorkPhone.Number != null)
            $get('txtWPExtension').value = results.WorkPhone.Extension;
        if (results.Email != null)
            $get('txtEmail').value = results.Email;
    }
</script>

但在那之前,我们需要为我们的扩展器添加一些客户端行为。我们需要将扩展器的 OnClientItemSelected 属性设置为上述 JavaScript 函数。此函数将解析 value 属性,该属性是从我们的 Web 服务传递的有效 JSON 数据,并使用这些解析后的数据设置相应的字段。

到此,我们的示例就完成了。现在您可以自己测试一下了。

历史

  • 2008-06-24 - 我的第一个 AJAX 自动扩展尝试
© . All rights reserved.