回发或回调参数无效,这个问题一直拖着,从用ASP.NET 2.0开始,用了各种各样的办法解决,到前一段时间,我使用的是Ajax的方法读取数据,客户端使用select控件和HiddenField控件结合的办法,服务器端从HiddenField中读取的数据回发
今天开始看MSDN中性能一节,跟着页面链接转着转着,看到这一节“在 ASP.NET 网页中不经过回发而实现客户端回调”的链接,切换过去,好东西。。。不知道为什么以前没有看这个,郁闷
记录几个链接:
如何:在 ASP.NET 网页中实现回调:http://msdn.microsoft.com/zh-cn/library/ms366518(VS.80).aspx
在 ASP.NET 网页中不经过回发而实现客户端回调:http://msdn.microsoft.com/zh-cn/library/ms178208(VS.80).aspx
客户端回调实现 (C#) 示例:http://msdn.microsoft.com/zh-cn/library/ms178210(VS.80).aspx
具有验证实现的客户端回调示例:http://msdn.microsoft.com/zh-cn/library/ms366515(VS.80).aspx
如何:通过对字符串应用 HTML 编码在 Web 应用程序中防止脚本侵入:http://msdn.microsoft.com/zh-cn/library/a2a4yykt(VS.80).aspx
下面说利用这个解决问题的办法,用两个级联的DropDownList做例子,大类使用服务器端控件DropDownList,小类使用客户端控件select,使用HiddenField记录小类的当前选项,这个做法是前一段时间用Ajax做的时候想到的,这里不同的是,使用Ajax时,我在客户端读取数据,用这个方法呢,就是不回发实现回调,直接在本页面的服务器端脚本里取小类对应大类的全部数据
我说得很乱,乱七八糟,直接看文件好了,那个,已经没的好解释的了,文件里面都是带注释的,具体的东西,看MSDN是最好的,我想如果我说,也是搬MSDN的东西。。。要说明的是,在这里,我从服务器端返回的数据是对应大类的全部小类,这个字符串里的数据形式是这样子的:小类一编号|小类一名称+小类二编号|小类二名称
TwoDdl.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="TwoDdl.aspx.cs" Inherits="TwoDdl" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>测试DropDownList无回调</title>
<script type="text/ecmascript">
function GetSmallClass()
{
var ddl = document.getElementById("DropDownList1");
var myid = ddl.options[ddl.selectedIndex].value;
CallServer(myid, "");
}
function ReceiveServerData(rValue)
{
document.getElementById("hfAll").value = rValue;
SetSmallClassItem();
}
function SetSmallClassItem()
{
var ddl, obj, str, text, value, index, indexForOp, strForOp, sValue;
obj = document.getElementById("hfAll");
ddl = document.getElementById("smallClass");
if(obj == null || ddl == null) return;
//取所有小类的字符串
str = obj.value;
ddl.options.length = 0;
//开始分解每一个选项
indexForOp = str.indexOf("+");
if(indexForOp == -1) return;
while(indexForOp > -1)
{
strForOp = str.substring(0, indexForOp);
str = str.substring(indexForOp + 1);
index = strForOp.indexOf("|");
text = strForOp.substring(0, index);
value = strForOp.substring(index + 1);
ddl.options[ddl.options.length] = new Option(value, text);
indexForOp = str.indexOf("+");
}
//最后一个选项
index = str.indexOf("|");
if(index > -1)
{
text = str.substring(0, index);
value = str.substring(index + 1);
ddl.options[ddl.options.length] = new Option(value, text);
}
//初始化当前选项
sValue = document.getElementById("hfSID").value;
if(sValue != "")
{
ddl.value = sValue;
if(ddl.selectedIndex == -1)
{
ddl.selectedIndex = 0;
SetValue(ddl);
}
}
else
{
//把现在的选项设置到HiddenField中记录
SetValue(ddl);
}
}
//把每一个小类选项都设置到TextBox记录
function SetValue(ddl)
{
var obj;
obj = document.getElementById("hfSName");
if(obj) { obj.value = ddl.options[ddl.selectedIndex].text; }
obj = document.getElementById("hfSID");
if(obj) { obj.value = ddl.options[ddl.selectedIndex].value; }
}
addLoadEvent(SetSmallClassItem);
function addLoadEvent(func)
{
var oldonload = window.onload;
if(typeof window.onload != 'function') { window.onload = func; }
else { window.onload = function() { oldonload(); func(); } }
}
</script>
</head>
<body>
<form id="form1" runat="server">
<p>
大类:
<asp:DropDownList ID="DropDownList1" runat="server" OnDataBound="DropDownList1_DataBound"></asp:DropDownList>
</p>
<p>
小类:
<select id="smallClass" onchange="SetValue(this);"></select>
<asp:HiddenField ID="hfAll" runat="server" /><asp:HiddenField ID="hfSName" runat="server" /><asp:HiddenField ID="hfSID" runat="server" />
</p>
<p>
<asp:Button ID="Button1" runat="server" Text="提交" OnClick="Button1_Click" />
<br />
<asp:Literal ID="Literal1" runat="server"></asp:Literal>
</p>
</form>
</body>
</html>
TwoDdl.aspx.cs
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class TwoDdl : System.Web.UI.Page, System.Web.UI.ICallbackEventHandler
{
protected static System.Collections.Specialized.ListDictionary bClass;
protected static DataTable sClass;
protected String returnValue;
protected void Page_Load(object sender, EventArgs e)
{
#region 添加客户端脚本callbackScript
String cbReference = Page.ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context");
String callbackScript;
callbackScript = "function CallServer(arg, context)" + "{ " + cbReference + ";}";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "CallServer", callbackScript, true);
#endregion
//不回大类下拉菜单的onchange事件
DropDownList1.Attributes.Add("onchange", "GetSmallClass();");
//初始化两个分类的数据
if (!IsPostBack)
{
IniClass();
bClassDataBind();
}
}
#region 每次大类数据更新后,重调小类,服务器端只更新hfAll,客户端调用SetSmallClassItem设置选项
protected void DropDownList1_DataBound(object sender, EventArgs e)
{
hfAll.Value = SetSmallClassHiddenText(DropDownList1.SelectedValue);
}
#endregion
#region 模拟提交
protected void Button1_Click(object sender, EventArgs e)
{
Literal1.Text = "大类:" + DropDownList1.SelectedValue + "(" + DropDownList1.SelectedItem.Text + ")<br />小类:" + hfSID.Value + "(" + hfSName.Value + ")";
}
#endregion
#region 实现ICallbackEventHandler接口的两个方法
//实现 ICallbackEventHandler 接口的 RaiseCallbackEvent 方法
public void RaiseCallbackEvent(String eventArgument)
{
returnValue = SetSmallClassHiddenText(eventArgument);
}
//实现 ICallbackEventHandler 接口的 GetCallbackResult 方法
public String GetCallbackResult()
{
return returnValue;
}
#endregion
#region 初始化两个DropDownList控件
private void IniClass()
{
bClass = new System.Collections.Specialized.ListDictionary();
bClass.Add(12, "积木");
bClass.Add(10, "魔方");
bClass.Add(23, "拼板");
bClass.Add(17, "智力");
sClass = new DataTable();
sClass.Columns.Add("bClassID", typeof(Int32));
sClass.Columns.Add("sClassID", typeof(Int32));
sClass.Columns.Add("sClassName", typeof(string));
sClass.Rows.Add(new Object[] { 12, 1, "乐高" });
sClass.Rows.Add(new Object[] { 12, 2, "蓝猫奇迹" });
sClass.Rows.Add(new Object[] { 12, 3, "滚珠轨道" });
sClass.Rows.Add(new Object[] { 10, 4, "二阶魔方" });
sClass.Rows.Add(new Object[] { 10, 5, "三阶魔方" });
sClass.Rows.Add(new Object[] { 10, 6, "四阶魔方" });
sClass.Rows.Add(new Object[] { 23, 7, "万能方块" });
sClass.Rows.Add(new Object[] { 23, 8, "新思维金字塔" });
sClass.Rows.Add(new Object[] { 23, 9, "立体方块" });
sClass.Rows.Add(new Object[] { 17, 10, "数字数独棋" });
sClass.Rows.Add(new Object[] { 17, 11, "字母数独棋" });
sClass.Rows.Add(new Object[] { 17, 12, "数和棋" });
sClass.Rows.Add(new Object[] { 17, 13, "加七游戏" });
}
private void bClassDataBind()
{
//绑定大类
DropDownList1.DataSource = bClass;
DropDownList1.DataTextField = "value";
DropDownList1.DataValueField = "key";
DropDownList1.DataBind();
}
#endregion
#region 取大类选项对应的所有小类,用+链接后返回
private string SetSmallClassHiddenText(string bClassID)
{
string returnValue = "";
try
{
DataRow[] drs;
drs = sClass.Select("bClassID=" + bClassID);
if (drs.Length > 0)
{
foreach (DataRow dr in drs)
{
if (returnValue.Equals(""))
{
returnValue += dr["sClassID"].ToString() + "|" + dr["sClassName"].ToString();
}
else
{
returnValue += "+" + dr["sClassID"].ToString() + "|" + dr["sClassName"].ToString();
}
}
}
}
catch (NullReferenceException)
{
returnValue = "-1";
}
return returnValue;
}
#endregion
}