简单实现AJAX: ASP.NET2.0 中回调的实现及常见问题的解决

本文示例代码
    接触asp.net时间并不长,对其中的很多新技术抱有浓厚的兴趣,最近在项目中碰到需要实现无刷新更新数据控件的问题,起初考虑使用ajax.pro,atlas实现,但感觉这两种实现对于自己的需求来说都过于重量级了,况且要引用第三方的dll,最终选择asp.net自带的回调接口实现了自己的要求,以下是说明,希望能给刚接触asp.net回调的朋友一点帮助。

    要实现无刷新更新数据控件需要分三步走:
        1. 客户端脚本触发回调方法
        2. 服务器端代码响应回调,并更新数据控件,将更新后的数据控件内容(html编码)发回客户端
        3. 客户端代码根据发回的内容重绘该数据控件

    示例代码中,空白的页面上有三个DropDownListBox控件DropDownListBox_A,DropDownListBox_B和DropDownListBox_C,最终的目的是实现在页面不刷新的情况下当DropDownListBox_A的选择更改时动态的更新DropDownListBox_B和DropDownListBox_C的内容,实现联动。

    在服务器端,首先要让自己的页面实现ICallbackEventHandler接口,如:
        public partial class _Default : System.Web.UI.Page, ICallbackEventHandler
    然后在页面上添加如下三个方法及一个公共string,固定套路:
        private string str_content;
        //    接收客户端传来的参数
        public void RaiseCallbackEvent(string the_string)
        {
            str_content = the_string;
        }

        //    将结果发回客户端
        public string GetCallbackResult()
        {
            string[] parts = str_content.Split('|');
            return (string)GetType().GetMethod(parts[0]).Invoke(this, new object[] { parts[1] });
        }

        //  返回指定控件的Html编码
        private string RenderControl(Control control)
        {
            StringWriter writer1 = new StringWriter(CultureInfo.InvariantCulture);
            HtmlTextWriter writer2 = new HtmlTextWriter(writer1);

            control.RenderControl(writer2);
            writer2.Flush();
            writer2.Close();

            return writer1.ToString();
        }

        然后声明一个更新数据控件的方法,比如示例中的
        public string BindDropDownList_B(string str_index)
        {
            //  简单绑定
            DropDownList_B.Items.Clear();
            for (int i = 0; i < 20; i++)
            {
                ListItem newItem = new ListItem();
                newItem.Text = string.Format("{0} - B{1}", str_index, i.ToString());
                DropDownList_B.Items.Add(newItem);
            }

            return RenderControl(DropDownList_B);
        }

        public string BindDropDownList_C(string str_index)
        {
            DropDownList_C.Items.Clear();
            for (int i = 0; i < 30; i++)
            {
                ListItem newItem = new ListItem();
                newItem.Text = string.Format("{0} - C{1}", str_index, i.ToString());
                DropDownList_C.Items.Add(newItem);
            }

            return RenderControl(DropDownList_C);
        }

        在客户端,你需要将两个数据控件的Html编码用<span></span>包起来,id分别为span_a和span_b,并在header中声明如下脚本:
        <script language="javascript" type="text/javascript">
        //  DropDownList_A的change
        function OnChanged()
        {
            var context = span_b;
            var theControl = document.getElementById("DropDownList_A");
            //  调用服务器方法BindDropDownList_B,并将A当前选择的index传过去
            var arg = "BindDropDownList_B|" + theControl.selectedIndex;
        
            <%= ClientScript.GetCallbackEventReference(this, "arg", "UpdataDropDownList_B", "context")%>;
        }
    
        function UpdataDropDownList_B(result, context)
        {
            //  重画控件
            context.innerHTML = result;
            //  避免同时更新失败
            setTimeout("elsefunction()", 1);
        }
    
        function elsefunction()
        {
            var context = span_c;
            var theControl = document.getElementById("DropDownList_A");        
            var arg = "BindDropDownList_C|" + theControl.selectedIndex;
        
            <%= ClientScript.GetCallbackEventReference(this, "arg", "UpdateDropDownList_C", "context")%>;
        }
    
        function UpdateDropDownList_C(result, context)
        {
            context.innerHTML = result;    
        }
        </script>

    最后在Page_Load中为DropDownList_A添加onchange属性
            DropDownList_A.Attributes.Add("onchange", "OnChanged()"); 
    直接点运行吧,注意看IE的进度条。是不是无刷新实现了下拉列表的联动:)

    需要说明的是,如果在Javascript脚本的OnChanged中接连两次回调服务器方法的话只有最后一次奏效,并且会有JavaScript报错,原因是微软的客户端回调实现代码中有一个缺陷:无论客户端回调了多少次,只要有一次回调完成,则视所有回调均完成,不是线程安全的!所以上述代码中使用了setTimeout做了中转,具体原因详见http://developers.de/files/279/download.aspx.
    
    以上代码虽很好的完成了无刷新前提下的数据控件更新,但仍有一个问题至今没有解决,就是虽然控件的数据重新更新了,但是状态却还是最后一次PostBack时的状态(本例中为初始状态),如果你去取某个下拉框的值,仍就是初始值,不知道哪位朋友有这方面的解决办法,万分感谢!

你可能感兴趣的:(asp.net)