利用asp.net 2.0的客户端回调功能制作下拉框无限级联动

        记得以前做asp的时候,常会碰到下拉框多级联动,比如说在注册的时候,需要选择省和城市,这就需要二级联动,那个时候一个普遍的做法就是利用javascript脚本来实现,先把数据从数据库中读取出来,放到javascript的数组中,在下拉框的onchange事件触发时,就可以直接从javascript的数组中读取想要的数据。后来在asp.net 1.0中开发时,这种方法也通用,但如果要多级的话,有一个很大的缺点,就是它需要把数据一次性全部读到javascript的数组中,如果数据非常庞大的话,这部分开销是很大的,有时候不把数据放到数据中中,而是直接写在javascript中,这样不易于维护,而且代码也太长,如果要开发可以无限级联的话,那更是比较头痛。自从asp,net 2.0问世后,开始学习新技术,发现asp,net2.0不仅在控件上,功能上都产生了大变化,而且在对javascript客户脚本的调用功能也更加强大了,特别是出现了ajax功能,即客户端回调功能(当然这只是一个小小的ajax功能,如果要实现功能更强大的无刷新可看atlas),利用这个特性可以很方便的开发现无限级联动的下拉框效果。
        1、先在数据库里建立相应的数据表如下:

 2、建立读取数据表的函数,这里就不写出来了,我想每个人都会有不同的方法去实现这一功能。
    3、接下来,我们就可以进行页面设置了,我们先做一个二级联动的效果,在页面上放置二个下拉框控件,上面一个为TestDropDownList,下面一个为Item1,再加入一个objectdatasource控件,用来读取parentId为0的所有记录绑定到TestDropDownList下拉框中,如下图:

  如果要使用客户端回调,必须要实现System.Web.UI.ICallbackEventHandler接口。
1public partial class Test : System.Web.UI.Page , System.Web.UI.ICallbackEventHandler
2{
  该接口下面,有二个方法:
        a)、void System.Web.UI.ICallbackEventHandler.RaiseCallbackEvent(string eventArguent)
        该方法接收客户端传过来的参数enentArguent,这个参数好象只能是string型,并且没有返回值,我们可以根据传过来的参数,来执行相应的功能,在这里我们不能对页面进行重新绑定等操作,但能够跟数据库进行交互操作,如读取、删除、插入等操作,在本文的例子中,这里从客户端传过来的是parentId的值,再从数据库中读取parentId为相应值的所有记录,具体代码如下:
 1void System.Web.UI.ICallbackEventHandler.RaiseCallbackEvent(string eventArguent)
 2    {
 3        DataSet ds = new GetData().TestByParentId(Convert.ToInt32(eventArguent));
 4        foreach(DataRow row in ds.Tables[0].Rows)
 5        {
 6            if (result.Equals(string.Empty))
 7            {
 8                result = row["pkId"+ "@" + row["name"].ToString();
 9            }

10            else 
11            {
12                result = result + "," + row["pkId"+ "@" + row["name"].ToString();
13            }

14        }

15    }

  在这里,通过TestByParentId(Convert.ToInt32(enentArguent))函数读到相应数据,并把得到的数据作了一些处理,这个为什么要这样做,请继续往下看。这里的result为string型变量。
    
        b)、string System.Web.UI.ICallbackEventHandler.GetCallbackResult()
        这是第二个方法,该方法没有参数,返回只能返回string型。这个方法是用来数据回调的,上面那个方法接收客户端传过来的参数,进行处理后,还要把处理后的我们想要的数据传回到客户端去执行,才会有用。这里我们也看到了,由于该方法只能返回string型,而在下拉框必须有二个值,一个是DataValue,另一个是DataText,所以在上面的方法中,通过@符号,把这二个值合在一起,便于在客户端程序中进行分离。这个方法功能很简单,就是把result返回即可,如下:
1string System.Web.UI.ICallbackEventHandler.GetCallbackResult()
2    {
3        return result;
4    }

  现在我们实现了System.Web.UI.ICallbackEventHandler接口下的全部方法,接下来我们就可以来写客户端的程序了,用javascript来实现。这里主要也有二个方法,第一个方法用来接受下拉框控件的onchange事件触发响应,另一个用来接收string System.Web.UI.ICallbackEventHandler.GetCallbackResult()方法传递过来的result值,并做相应处理,把数据绑定到第二个下拉框中去,实现 二级联动。主要代码如下
        a)、第一个方法
       
1 function CallServer(input, context)
2    {
3        context.length=0;
4        context.options[context.length]=new Option("数据读取中","0");
5        
6        arg = input.value;
7        <%=callback %>
8    }

  这里有二个参数,input是用来触发onchange的下拉框控件名称,context是要级联的下拉框名称,这里在数据还没有绑定之前,级联下拉框显示“数据读取中...”字样。arg接收input下拉框的值,这个值以后是传递到上面的eventArguent参数中去,其中的<%=callback%>我们下面再介绍。
        b)、第二个方法
   
 1 function ReceiveServerData(result, context)
 2    {
 3        context.length=0;
 4        var arrData = result.split(",");
 5        for (var i = 0; i < arrData.length; i++)
 6        {
 7            var data = arrData[i].split("@");
 8            context.options[context.length]=new Option(data[1],data[0]);
 9        }

10       
11    }

       这里也有二个参数,其中result,就是接收上面讲到的result值,而context同第一个方法的context。这里通过js的split方法,把数据进行处理,再绑定到context控件中去,通过这个就可以在第二个下拉框中出现相应的值了。
  做到这里基本上已经大功告成了,不过还有最后一步,这也是最重要的一步,我们现在做的只是客户端归客户端,服务器方法归服务器方法,那么怎么样把这二个联系起来呢,这也是实现客户端回调的关键部分,这里需要使用Page.ClientScript.GetCallbackEventReference方法,下面是摘自MSDN2上的对ClientScript.GetCallbackEventReference(……)的详细说明。
  
  public string GetCallbackEventReference (Control control,string argument,string clientCallback,string context)
  
    参数:
  
  参数 作用
  control 处理客户端回调的服务器 Control。该控件必须实现 ICallbackEventHandler 接口并提供 RaiseCallbackEvent 方法。
  argument 从客户端脚本传递一个参数到服务器端的RaiseCallbackEvent 方法。
  clientCallback 一个客户端事件处理程序的名称,该处理程序接收服务器端事件返回的结果。
  context 启动回调之前在客户端的客户端脚本信息。脚本的结果传回给客户端事件处理程序。
  返回值 调用客户端回调的客户端函数的名称。
  
    下面是ClientScriptManager.GetCallbackEventReference 方法的重载列表
  
  名称 说明
  ClientScriptManager.GetCallbackEventReference (Control, String, String, String) 获取一个对客户端函数的引用;调用该函数时,将启动一个对服务器端事件的客户端回调。此重载方法的客户端函数包含指定的控件、参数、客户端脚本和上下文。
  ClientScriptManager.GetCallbackEventReference (Control, String, String, String, Boolean) 获取一个对客户端函数的引用;调用该函数时,将启动一个对服务器端事件的客户端回调。此重载方法的客户端函数包含指定的控件、参数、客户端脚本、上下文和布尔值。
  ClientScriptManager.GetCallbackEventReference (Control, String, String, String, String, Boolean) 获取一个对客户端函数的引用;调用该函数时,将启动一个对服务器端事件的客户端回调。此重载方法的客户端函数包含指定的控件、参数、客户端脚本、上下文、错误处理程序和布尔值。
  ClientScriptManager.GetCallbackEventReference (String, String, String, String, String, Boolean) 获取一个对客户端函数的引用;调用该函数时,将启动一个对服务器端事件的客户端回调。此重载方法的客户端函数包含指定的目标、参数、客户端脚本、上下文、错误处理程序和布尔值。  

        主要实现如下:
    在page_load里加入下面语句
   
1callback = Page.ClientScript.GetCallbackEventReference(this"arg""ReceiveServerData""context");

    其中,arg就是用来从客户端传递参数,最终传到enentArguent中,ReceiveServerData是一个客户端方法,用来接收服务器端回调过来的数据。

    再把callback这个字符串放在第一个客户端方法下面(请看上面的第一个客户端方法)

    这个完成后,我们只要把第一个下拉框的onchange客户端事件加入就可以了
    在page_load里加入
   
1TestDropDownList.Attributes["onchange"= "javascript:CallServer(TestDropDownList , Item1)";



    做完所有这些,程序应该能够正常动行了

  现在二级联动已经成功,那怎么能够实现多级的呢,其实大家只要仔细的看一下,就不难发现,当我触到一个下拉框的onchange事件,通过callServer读取值,再通过<%callback%>来启动 void System.Web.UI.ICallbackEventHandler.RaiseCallbackEvent(string eventArguent)这个方法,把数据处理后,通过string System.Web.UI.ICallbackEventHandler.GetCallbackResult()方法返回,再由ReceiveServerData客户端来把数据绑定到相应原下拉框中,而这里的二个互动的下拉框都是通过参数来传递的, TestDropDownList.Attributes["onchange"] = "javascript:CallServer(TestDropDownList , Item1)"; 这样的话,我们可以改变这里传递的控件参数名,就可以重复利用这四个方法,也就是这样就可以实现,无限级联动。我们再加入一个下拉框,取名Item2,我们只要在page_load中加入如下语句即可:

1Item1.Attributes["onchange"= "javascript:CallServer(Item1 , Item2)";

就就可以三级联动了,如果要四级,五级,只要加入下应的下拉框,并在page_load中加入相应的onchange事件触发,就可以实现了

不过这种方法目前还有一个很大的二个缺点:
    1、那就是当第一个选择后,第二个下拉框会出现相应的值,而第三个以及下面的几个不会变,只有再选择第二个下拉框的值后,第三个才会改变
    2、由于1的问题,导致如果第二个下拉框中只有一个值,那么第三个以及以下几个都不能发生改变了
不知道大家有没有好的解决方法,我相信应该有解决的方法的。
    由于本人水平有限,可能有不当之处,希望大家能够指正,谢谢!

posted on 2006-05-25 11:38  李.net  阅读(...)  评论(...编辑  收藏

导航