使用 ASP.NET 2.0 回调从动态创建的控件访问数据
存储和检索来自动态创建的控件的数据输入,无需在回发后重新创建控件。
引言
在使用 ASP.NET 2.0 进行开发时,我遇到一种需要动态创建控件的情况。 像往常一样,我开始通过搜索我经常访问的网站和博客来寻找最佳实践方法。 我发现的每个示例都提到了在回发时重新创建动态创建的控件以检索用户已输入或更改的数据的需求。 这是有道理的:毕竟,如果没有控件,控件的视图状态数据就变成了孤立数据。 如果您不再需要之前在回发之前创建的控件怎么办? 仅仅为了检索已有的东西而重新创建它们真的有意义吗? 我认为没有,所以我开始寻找其他替代方案。 我发现的东西已经存在,只是等待被使用,就像我喜欢编写的代码一样,它干净而简单。
问题
现在我已经设置了问题,让我们更仔细地看看它。 假设我需要查询数据库以确定需要为 Web 窗体动态创建多少个TextBox
,该窗体将询问用户需要回答的问题。 在从用户那里收集其他数据之前,我可能不确定需要显示多少个问题。 然后我可以查询数据库以查看需要创建多少个TextBox
,并创建每个TextBox
以在我的 Web 窗体上显示。
使用代码
以下代码将每行创建一个TextBox
,为每个TextBox
分配一个 ID,并设置属性以在用户离开TextBox
导致“OnFocusOut
”事件触发时运行一个名为“processText
”的 JavaScript(“客户端”)函数。
// This is the data returned from a DataSet.
DataSet DS = new DataSet();
DS = Run the code to query the database.
Session["TextBoxCount"] = DataSet[“TextBoxNumber”].ToString();
// This section creates the controls.
for (int a = 0; a < int.Parse(Session["TextBoxCount"].ToString()); a++)
{
TableRow tr = new TableRow();
TableCell tc = new TableCell();
TextBox tb = new TextBox();
tb.Attributes.Add("runat", "Server");
tb.Attributes.Add("OnFocusOut", "processText(" + a + ")");
tb.EnableViewState = false;
tb.MaxLength = 128;
tb.ID = "TextBox" + a;
tc.Controls.Add(tb);
tr.Cells.Add(tc);
table.Rows.Add(tr);
}
如上所述,解决方案干净而简单。 我们都听说过关于 AJAX 的狂热,对吧? 好吧,在 Jesse James Garrett 创造 AJAX 这个词之前,XMLHttpRequest
和 XMLHttpResponse
可供为 IE 5.0 编码的程序员和 Web 开发人员使用。 ASP.NET 2.0 包含一个类似于 C 和 C++ 开发人员在需要访问远程 API 中的函数时习惯在应用程序中使用的回调函数。 ASP.NET 2.0 中的这种回调方法允许您基本上进行压缩的回发,而无需重新加载页面内容。 据我所知,我是唯一将回调方法称为压缩回发的人,我这样做是因为它使用相同的基类,而且如果您单步执行回调方法,您将看到该页面确实回发了。
因此,您需要做的第一件事是确保您的页面在代码隐藏中实现 ICallbackEventHandler
。
//Example:
public partial class index_aspx : System.Web.UI.Page,
ICallbackEventHandler
现在,在 Page_Load
中,我们需要注册我们的客户端回调。
//Example:
ClientScriptManager cm = Page.ClientScript;
String cbRef = cm.GetCallbackEventReference(this,
"arg", "ReceiveServerData", "context");
String callbackscript = "function callserver(arg," +
"context) {" + cbRef + "}";
cm.RegisterClientScriptBlock(this.GetType(),
"CallServer", callbackscript, true);
接下来,实现 RaiseCallbackEvent
,它是处理客户端调用的服务器端函数。
//Example:
public void RaiseCallbackEvent(String eventArgument)
{
int iTyped = int.Parse(eventArgument.Substring(0, 1).ToString());
if (iTyped != 0) //Process Text Fields
{
int Txtid = int.Parse(eventArgument.Substring(1, 1).ToString());
string TxtData = eventArgument.Substring(2);
int fields = int.Parse(Session["TextBoxCount "].ToString());
string[] strTArray = new string[fields];
if (Session["TextDataArray"].ToString() != "")
{
strTArray = (string[])Session["TextDataArray "];
}
strTArray[Txtid] = TxtData;
Session["TextDataArray "] = strTArray;
this.sGetData = "Done";
}
}
在上面的代码片段中,TextDataArray
是一个会话变量,用于存储来自每个TextBox
的数据。 StrTArray
是一个数组,我们在每次回调 RaiseCallbackEvent
时都会填充该数组。 一旦我们返回到客户端,StrTArray
就会被销毁,并且该数组作为对象存储在 Session["TextDataArray"]
中。
我们还需要添加将数据返回到客户端的方法。
public String GetCallbackResult()
{
return this.sGetData;
}
客户端
客户端脚本非常简单。 当“GetCallbackResult
”将结果从服务器端传回时,它会被发送到“ReceiveServerData
”函数,您可以在其中以您的应用程序所需的任何方式处理数据。 在此示例中,我们只是将结果传递到一个警报框中。
function processText(n)
{
TBox = document.getElementById("TextBox" +n);
var data = document.all[TBox].value;
callserver("1"+n+data);
}
function ReceiveServerData(arg, context)
{
alert(arg);
}
完整代码
我们在这里所做的只是将用户输入的数据传回服务器,创建一个一维数组,并将该数组存储在会话变量中,以便我们在需要时使用。
代码后置
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 _Default : System.Web.UI.Page, ICallbackEventHandler
{
string sGetData = "";
protected void Page_Load(object sender, EventArgs e)
{
ClientScriptManager cm = Page.ClientScript;
String cbRef = cm.GetCallbackEventReference(this,
"arg", "ReceiveServerData", "context");
String callbackscript = "function callserver(arg," +
"context) {" + cbRef + "}";
cm.RegisterClientScriptBlock(this.GetType(),
"CallServer", callbackscript, true);
}
public void RaiseCallbackEvent(String eventArgument)
{
int iTyped =
int.Parse(eventArgument.Substring(0, 1).ToString());
if (iTyped != 0) Process Text Fields
{
int Txtid =
int.Parse(eventArgument.Substring(1, 1).ToString());
string TxtData = eventArgument.Substring(2);
int fields =
int.Parse(Session["TextBoxCount"].ToString());
string[] strTArray = new string[fields];
if (Session["TextDataArray"].ToString() != "")
{
strTArray = (string[])Session["TextDataArray"];
}
strTArray[Txtid] = TxtData;
Session["TextDataArray"] = strTArray;
this.sGetData = "Done";
}
}
public String GetCallbackResult()
{
return this.sGetData;
}
protected void Button1_Click(object sender, EventArgs e)
{
Session["TextBoxCount"] = "3";
// This section creates the controls.
for (int a = 0; a <
int.Parse(Session["TextBoxCount"].ToString()); a++)
{
TableRow tr = new TableRow();
TableCell tc = new TableCell();
TextBox tb = new TextBox();
tb.Attributes.Add("runat", "Server");
tb.Attributes.Add("OnFocusOut",
"processText(" + a + ")");
tb.EnableViewState = false;
tb.MaxLength = 128;
tb.ID = "TextBox" + a;
tc.Controls.Add(tb);
tr.Cells.Add(tc);
ctrlTable.Rows.Add(tr);
}
}
protected void Button2_Click(object sender, EventArgs e)
{
int fields = int.Parse(Session["TextBoxCount"].ToString());
string[] strTArray = new string[fields];
if (Session["TextDataArray"].ToString() != "")
{
strTArray = (string[])Session["TextDataArray"];
}
for (int a = 0; a <
int.Parse(Session["TextBoxCount"].ToString()); a++)
{
if (sGetData != "")
{
this.sGetData = sGetData + "~" + strTArray[a].ToString();
}
else
{
this.sGetData = strTArray[a].ToString();
}
}
}
}
客户端
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-W3CDTD XHTML 1.0 TransitionalEN"
"http:www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http:www.w3.org/1999/xhtml" >
<head runat="server">
<title>Dynamic TextBox Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Table ID="ctrlTable"
runat="server"></asp:Table>
<br/>
<asp:Button ID="Button1" runat="server"
OnClick="Button1_Click"
Text="Create TextBoxes" />
<asp:Button ID="Button2" runat="server"
Text="Postback and get data"
OnClick="Button2_Click" />
</form>
</body>
</html>
<script type="text/javascript">
function processText(n)
{
TBox = document.getElementById("TextBox" + n);
var data = TBox.value;
callserver("1"+n+data);
}
function ReceiveServerData(arg, context)
{
alert(arg);
}
</script>