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

基于 Ajax.NET 的查找服务器控件实现

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.27/5 (23投票s)

2005年9月1日

4分钟阅读

viewsIcon

137021

downloadIcon

583

本文介绍如何基于 Ajax.NET 框架构建一个查找服务器控件。

引言

AJAX 是当今最流行的词汇之一。这个概念并非新鲜事物,但不知何故,在过去半年里变得流行起来。随着 Web 应用程序的普及,用户对更丰富、更快的界面提出了要求。而 AJAX 非常有助于改善 Web 应用程序的用户体验。

让我向您展示一个真实用户需求的例子。我们的一位客户需要一种快速选择用户故事和 Bug 的方法。例如,Bug 可以链接到用户故事,并且有一个用于此目的的下拉列表。但是,当下拉列表中有大约 100 个项目时,它根本无法使用,而查找控件将使选择更简单(类似于 Google Suggest)。因此,我们决定在我们的产品中使用 AJAX 来实现这些功能,改进用户界面,并使其响应更灵敏。

AJAX 对我来说是全新的。我曾经读过一些关于它的通用文章来了解一些概念,但由于缺乏工具和现成的库而没有尝试过。然而,最近我发现了 Ajax.NET – 一个非常强大的框架,支持异步回调。其中的示例很简单,所以我决定用它来实现我的目标。

在本文中,我将描述使用 Ajax.NET 创建查找控件的经验。要构建查找控件,您需要做几件事:

  1. 一个服务器方法,它将返回匹配记录的列表。
  2. 一个 JavaScript,它将处理回发并显示匹配记录的列表。
  3. 在 ASPX/ASCX 页面上的一个输入字段。

我不会在这里描述 Ajax.NET 的安装,因为它非常简单,而且有一些很棒的资源供您查看

服务器端部分

这部分确实很简单。我需要实现的只是一个简单的返回匹配记录 `ArrayList` 的方法,并注册包含该方法的类。

public class Main : Page
{

    private void Page_Load(object sender, EventArgs e)
    {
        Utility.RegisterTypeForAjax(typeof (Main));
    }

    [AjaxMethod()]
    public ArrayList GetSearchItems(string query)
    {
        // use real method ti query data from database instead

        ArrayList items = GetRecords();

        ArrayList matchItems = new ArrayList();

        foreach (string item in items)
        {
            if (item.ToLower().StartsWith(query.ToLower()))
                matchItems.Add(item);
        }
        return matchItems;
    }

    private ArrayList GetRecords()
    {
        ArrayList items = new ArrayList();
        items.Add("Ted");
        items.Add("Teddy");
        items.Add("Mark");
        items.Add("Alfred");
        return items;
    }
. . .

`GetSearchItems` 方法从任何源获取所有记录的列表,并过滤掉那些以 `query` 参数开头的记录。`query` 是用户在输入字段中键入的内容。

客户端部分

首先,我决定编写一个非常简单的 JavaScript,它会在查询输入字段的正下方显示一个包含找到记录的 `DIV`。我心想“又近了一步”。但需要选择下面的其中一项。最简单的方法是将所有项目变成超链接,并在单击时用正确的值填充查询字段。以下是我的成果:

<INPUT id=search type=text name=search runat="server"
autocomplete ="off">
<div id="list"></div>

需要 `autocomplete="off"` 来告知浏览器不要显示输入字段的可能值。否则,我们的控件将无法正常工作。

function GetSearchItems_CallBack(response) {
    var div = document.getElementById("list");
    div.innerHTML = "";
    if (response.value != null && response.value.length > 0) {
        for (var i = 0; i < response.value.length; ++i){
        div.innerHTML += 
          "<a href=\"javascript:Fill('" + response.value[i] + "');\">" + 
                                         response.value[i] + "</a><br />";
    } 
}

JavaScript 的 `GetSearchItems_CallBack` 函数应该绑定到 `onkeydown` 事件。这可以在代码隐藏文件或直接在 `*.aspx` 页面上完成。让我们使用代码隐藏文件。

private void Page_Load(object sender, EventArgs e)
{
    search.Attributes.Add("onkeydown", 
                  "javascript:Main.GetSearchItems(this.value,
                                       GetSearchItems_CallBack);");
    Utility.RegisterTypeForAjax(typeof ( Main ));
}

结果如下:

虽然这是最简单的方法,但它并不十分可用。您输入一些内容,然后单击出现的列表中的一个链接 – 操作太多了。真正需要的是一些炫酷的键盘支持。用户应该能够使用上/下键进行列表导航,并使用 Enter 键完成选择。

寻找 JavaScript

我以前从未在 JavaScript 中处理过按键事件,并且懒得自己编写一个庞大而复杂的脚本。我懂 JavaScript,但不如 C# 熟练,所以我第一个反应是:“让我们找一些现成的东西来适应我们的需求。”我必须说,免费脚本并不多。我花了一个小时才找到一个不错的。所以不能错过这个引用。感谢 Julian Robichaux 提供了这个非常棒的脚本,附带了很棒的注释(这对于免费脚本来说很少见,对于商业脚本也是如此:))

该脚本提供了一个查询服务器的函数,但我需要一个自定义函数。幸运的是,唯一需要的更改是 `mainLoop` 函数。

mainLoop = function() {

        val = escape(queryField.value);
                      
        if(lastVal != val && searching == false){
                        
            var response = Main.GetSearchItems(val);
            showQueryDiv('smi', response.value); lastVal = val;
        }
                      
        setTimeout('mainLoop()', 100);
        return true;
};

应该通过 `onload` 处理程序启用该脚本。

<body onload="InitQueryCode('search')">

最终,我在很短的时间内得到了我想要的结果。但解决方案是不可重用的,所以我决定创建一个简单的服务器控件。

服务器控件

AJAX 查找服务器控件是一个非常简单的东西。现有解决方案的以下部分应该是可自定义的:

  • 回调函数的名称。
  • JavaScript 文件的路径。
  • 颜色,如匹配列表的背景和高亮,`div` 的内边距等。

可以发明其他东西,但我不需要更多,而且总的来说,如果近期不需要,我不喜欢增加复杂性。

实现相当简单。我们可以让我们的控件继承自 `TextBox`。然后,我们所需要做的就是设置一些变量并注册一些 JavaScript 函数。

using System;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace play
{
    /// <summary>

    /// AjaxLookup.cs

    /// </summary>

    public class AjaxLookup : TextBox
    {
        private string scriptFile = "";
        private string callBackFunction = "";
        private string backgroundColor = "#EEE";
        private string highlightColor = "#CCC";
        private string font = "Verdana";
        private string divPadding = "2px";
        private string divBorder = "1px solid #CCC";

        public string ScriptFile
        {
            get { return scriptFile; }
            set { scriptFile = value; }
        }

        public string CallBackFunction
        {
            get { return callBackFunction; }
            set { callBackFunction = value; }
        }

        public string BackgroundColor
        {
            get { return backgroundColor; }
            set { backgroundColor = value; }
        }

        public string HighlightColor
        {
            get { return highlightColor; }
            set { highlightColor = value; }
        }

        public string DivFont
        {
            get { return font; }
            set { font = value; }
        }

        public string DivPadding
        {
            get { return divPadding; }
            set { divPadding = value; }
        }

        public string DivBorder
        {
            get { return divBorder; }
            set { divBorder = value; }
        }

        public AjaxLookup()
        {
            this.Attributes.Add("autocomplete", "off");
        }

        protected override void Render(HtmlTextWriter writer)
        {
            base.Render(writer);

            // bind script that contains almost all logic

            Page.RegisterStartupScript("LoadScript", 
                 "<script language="'JavaScript'" src='" + ScriptFile + "'>" + 
                                                                 "</script>");

            // include UI settings

            string styles = String.Format(
                @"<script language="'JavaScript'">
                    var DIV_BG_COLOR = '{0}';
                    var DIV_HIGHLIGHT_COLOR = '{1}';
                    var DIV_FONT = '{2}';
                    var DIV_PADDING = '{3}';
                    var DIV_BORDER = '{4}';
                </script>",
                BackgroundColor, HighlightColor, DivFont, 
                                      DivPadding, DivBorder);

            Page.RegisterStartupScript("LookupStyles", styles);

            // initialize postback handling 

            Page.RegisterStartupScript(
                "RegisterScript",
                "<script language="'JavaScript'">" + 
                    "InitQueryCode('" + this.ClientID + "')</script>");

            // set correct calllback function

            Page.RegisterStartupScript("RegisterCallBack", 
                               @"<script language="'JavaScript'">
                
                mainLoop = function() {

                    val = escape(queryField.value);
                      
                    if(lastVal != val && searching == false){
                        
                        var response = " + CallBackFunction + @"(val);
                        showQueryDiv('smi', response.value); lastVal = val;
                    }
                      
                    setTimeout('mainLoop()', 100);
                    return true;};
                </script>");
        }
    }

控件可以这样使用:

<Ajax:AjaxLookup 
        Runat="Server" 
        id="search" 
        BackgroundColor="#EEE" 
        DivBorder="1px solid #CCC" 
        DivPadding="2px"  
        DivFont="Arial" 
        HighlightColor="#C30" 
        CallBackFunction="Main.GetSearchItems" 
        ScriptFile="lookup.js" />

这是查找控件在生产环境中的样子:

这个实现并非完美,但足够好,可以作为起点。您可以提高灵活性,添加一些额外的参数等等。

结论

总的来说,Ajax.NET 可以帮助实现许多有用的功能。从最简单的东西,如查找控件开始是合理的,但我希望将来我们项目中的许多 UI 部分将基于 AJAX。

联系方式

  • 联系邮箱:michael [at] targetprocess.com。
  • 博客.
© . All rights reserved.