让AutoCompleteExtender支持选中项的Id

在使用AutoCompleteExtender控件时,有时候我们希望同时返回选中项的文本和Id号,即支持键值对数据,比如利用AutoCompleteExtender选择员工时,选中一个员工姓名的同时,也将员工的Id号返回,这样我们就可以直接使用员工Id,下面介绍两种方法(本文使用.Net 2.0 版本说明具体步骤):

第一种方式:最直接的方式
主要有3个步骤:
1、改造返回字符串数组的WebServices方法,让返回的为NameVlue键值对数据,但仍旧为字符串数组格式.

以中自带的例子来说明,原代码为:
items.Add(prefixText + c1 + c2 + c3);
改为
items.Add(prefixText + c1 + c2 + c3 + "|" + Guid.NewGuid().ToString());
这里用分隔符来分割NameVlue键值对,以方便客户端取出。

2、改造JavaScript文件中AutoCompleteBehavior类的_update方法

_update方法中的completionItems参数,就是WebServices返回的JSON数据生成的JavaScript数组。
找到_update方法中的下面这句代码
itemElement.appendChild(document.createTextNode(this._getTextWithInsertedWord(text)));
改为
if(typeof( completionItems[i]) == "string" && completionItems[i].indexOf("|") >= 0)
{
    itemElement.setAttribute("title", completionItems[i].split("|")[1]);
    itemElement.appendChild(document.createTextNode(this._getTextWithInsertedWord(completionItems[i]).split("|")[0]));
}
else
{
    itemElement.appendChild(document.createTextNode(this._getTextWithInsertedWord(text)));
}
  
3、修改_setText方法,以便在选中一项suggestion的同时,获取其相应的Id
找到下面这句
element.value = text;
在此句下面加上
if($get(element.id + "Id"))
{
 $get(element.id + "Id").value = item.getAttribute("title");
}
在这里,还要在aspx页面上,在AutoComplete的TextBox后面加一个隐藏域,且Id号为AutoComplete的TextBox的Id号后再加“Id”,这个可以自己任意取,同时也可以不用隐藏域,也可以通过其他方法得到选中项的Id。


第二种方式:利用AutoCompleteBehavior中_update方法的变量pair

1、改造返回字符串数组的WebServices方法,让返回的为NameVlue键值对数据

你可以用下面三个方法中的任意一个

Code

 

 



[WebMethod]
public List<Pair> GetCompletionList2(string prefixText, int count)
{
    
if (count == 0)
    {
        count 
= 10;
    }

    
if (prefixText.Equals("xyz"))
    {
        
return new List<Pair>(0);
    }

    Random random 
= new Random();
    List
<Pair> items = new List<Pair>(count);
    
for (int i = 0; i < count; i++)
    {
        
char c1 = (char)random.Next(6590);
        
char c2 = (char)random.Next(97122);
        
char c3 = (char)random.Next(97122);

        items.Add( 
new Pair( prefixText + c1 + c2 + c3, Guid.NewGuid().ToString()));
    }

    
return items;
}

 

 

[WebMethod]
public string[] GetCompletionList3(string prefixText, int count)
{
    
if (count == 0)
    {
        count 
= 10;
    }

    
if (prefixText.Equals("xyz"))
    {
        
return new string[0];
    }

    Random random 
= new Random();
    List
<string> items = new List<string>(count);
    
for (int i = 0; i < count; i++)
    {
        
char c1 = (char)random.Next(6590);
        
char c2 = (char)random.Next(97122);
        
char c3 = (char)random.Next(97122);

        items.Add(String.Format(
"{{\"First\":\"{0}\", \"Second\":\"{1}\"}}", prefixText + c1 + c2 + c3, Guid.NewGuid().ToString()));
    }

    
return items.ToArray();
}

 

2、改造JavaScript文件中AutoCompleteBehavior类的_update方法

找到
catch (ex) {
    text = completionItems[i];
    value = completionItems[i];
}
改为
catch (ex) {
 try {
  if (completionItems[i].First) {
   text = completionItems[i].First;
   value = completionItems[i].Second;
  }
  if (completionItems[i].Value) {
   text = completionItems[i].Key;
   value = completionItems[i].Value;
  }
  else {
   text = completionItems[i];
   value = completionItems[i];
  }
 }
 catch (ex2) {}
}

3、修改_setText方法,以便在选中一项suggestion的同时,获取其相应的Id
找到下面这句
element.value = text;
在此句下面加上
if($get(element.id + "Id"))
{
 $get(element.id + "Id").value = itemElement._value;
}
在这里,也是在AutoComplete的TextBox后面加一个隐藏域,当然你也可以用其他手段。


这里需要说一下服务器端的 GetCompletionList3方法,实际上返回的每一个suggestion都是一个JSON文本,在客户端的_update方法中,有句代码为
var pair = Sys.Serialization.JavaScriptSerializer.deserialize('(' + completionItems[i] + ')');
此句代码只有在服务器端返回的每一个suggestion是一个JSON文本才会正确执行,因此我们的第一种方式和第二种方式中的GetCompletionList1和GetCompletionList2,这三个WebServices方法
返回的数据都不会使此句执行,真正执行的是catch里的代码,因为这三个WebServices方法返回的数据都会导致此句代码抛出异常。只有GetCompletionList3方法方法才会导致此句代码执行。

其实客户端使用Sys.Net.WebServiceProxy.invoke返回的数据已经进行了反串行化,已经是JavaScript对象了,从Sys.Net.WebRequestExecutor的get_object()方法就可以知道。


另外提一下就是在asp.net 2.0中当使用frame时,MicrosoftAjax.js中的一个小bug,这个bug在asp.net 3.5中已经修复。
在asp.net 2.0 的 Sys.UI.DomElement 对象中有个getLocation静态方法,里面有这句 offsetL += (f.frameBorder || 1) * 2 + ...

其中f.frameBorder与页面上设置的值紧密相关,frameBorder 属性设置或返回是否显示框架周围的边框,1表示有边框,0表示没有边框。由于我是仿照着别人的界面,使用了frame,是这样写的
<frame ... frameborder="NO"> frameBorder既不是1也不是0,造成f.frameBorder为NaN,导致getLocation方法返回的是NaN。因为MicrosoftAjax.js是嵌入的资源,无法修改,只好修改AjaxControlToolkit中的Common.js文件
找到里面的getLocation方法的最后一句,改为
var returnValue = Sys.UI.DomElement.getLocation(element);
if(isNaN(returnValue.x) && Sys.Browser.agent == Sys.Browser.InternetExplorer)
{
 // 这里将asp.net 3.5中MicrosoftAjax.js文件的getLocation代码复制过来,在这里不详细写了
 // 找到这句var offset = (f.frameBorder === "0" || f.frameBorder === "no") ? 2 : 0;
 // 替换为  var offset = (f.frameBorder === "0" || f.frameBorder === "no" || f.frameBorder === "NO" || isNaN(f.frameBorder)) ? 2 : 0;
}

posted @ 2008-09-28 23:24  要有好的心情  阅读(2304)  评论(1编辑  收藏  举报