[译]用PageMethods/AJAX填充HTML表格
这篇文章展示如何用ASP.NET AJAX的PageMethods方法与HTML表格来实现增删查改。在这里HTML表格充当一个轻量性的DataGrid的功能。
为了使用PageMethods方法,我们必须满足以下条件:
1.页面中必须包含ScriptManager控件
2.设置ScriptManager控件的EnablePageMethods属性为true
3.页面后台代码需要引用System.Web.Services命名空间
4.页面后台代码需要用[WebMethod]来标记PageMethods方法
首先我们先来实现查询功能
如上所说,在页面上增加一个ScriptManager控件并把属性EnablePageMethods设置为true。增加一个HTML按钮并设置它的onclick事件,然后增加一个带有thead,tbody和tfoot的HTML表格。既然HTML表格将被javascript调用,因而为其和它的body分别增加一个id。在这里,因为只使用HTML标记及控件,所有服务器端的控件将不能被PageMethods调用。
通过PageMethods调用的方法必须标记[WebMethod]并且必须是静态的方法。声明如下:
取数据的方法:
用来实现增删查改的javascript函数
使用ASP.NET AJAX的PageMethods方法的一些限制:
1.在[WebMethod]标记的方法中不能直接访问服务端控件(如textbox)
2.不能访问后台代码中声明的任何变量
为了使用PageMethods方法,我们必须满足以下条件:
1.页面中必须包含ScriptManager控件
2.设置ScriptManager控件的EnablePageMethods属性为true
3.页面后台代码需要引用System.Web.Services命名空间
4.页面后台代码需要用[WebMethod]来标记PageMethods方法
首先我们先来实现查询功能
如上所说,在页面上增加一个ScriptManager控件并把属性EnablePageMethods设置为true。增加一个HTML按钮并设置它的onclick事件,然后增加一个带有thead,tbody和tfoot的HTML表格。既然HTML表格将被javascript调用,因而为其和它的body分别增加一个id。在这里,因为只使用HTML标记及控件,所有服务器端的控件将不能被PageMethods调用。
ASPX页面如下:
代码
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods ="true" ></asp:ScriptManager>
<%--This click event handles loading data from the database--%>
<input id="btn_load" type="button" value="Load" onclick = "LoadData()" />
<br /><br />
<div>
<table style=" height: 100%; border: solid 1px #000" cellpadding="0" cellspacing="1" id="tbl_grid" border = "1">
<thead style = "background-color: #666; color: #fff">
<tr>
<td style="width: 100px;">
Column1
</td>
<td style="width: 500px;">
Column2
</td>
<td style="width: 150px;">
Edit
</td>
</tr>
</thead>
<tbody id="tbody_grid">
</tbody>
<tfoot>
<tr>
<td style="width: 100px;">
<input id="txt_addcol1" style ="width: 30px" type="text" />
</td>
<td style="width: 500px;">
<input id="txt_addcol2" type="text" style ="width: 300px" />
</td>
<td style="width: 150px;">
<%--This click event handles adding data to the database--%>
<input id="btn_add" type="button" onclick = "Add()" value="Add" />
</td>
</tr>
</tfoot>
</table>
</div>
</form>
</body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods ="true" ></asp:ScriptManager>
<%--This click event handles loading data from the database--%>
<input id="btn_load" type="button" value="Load" onclick = "LoadData()" />
<br /><br />
<div>
<table style=" height: 100%; border: solid 1px #000" cellpadding="0" cellspacing="1" id="tbl_grid" border = "1">
<thead style = "background-color: #666; color: #fff">
<tr>
<td style="width: 100px;">
Column1
</td>
<td style="width: 500px;">
Column2
</td>
<td style="width: 150px;">
Edit
</td>
</tr>
</thead>
<tbody id="tbody_grid">
</tbody>
<tfoot>
<tr>
<td style="width: 100px;">
<input id="txt_addcol1" style ="width: 30px" type="text" />
</td>
<td style="width: 500px;">
<input id="txt_addcol2" type="text" style ="width: 300px" />
</td>
<td style="width: 150px;">
<%--This click event handles adding data to the database--%>
<input id="btn_add" type="button" onclick = "Add()" value="Add" />
</td>
</tr>
</tfoot>
</table>
</div>
</form>
</body>
现在增加一个名为LoadData()的javascript函数,用来从数据库读取数据。PageMethod调用应该总是有一个成功的回调函数(此函数在PageMethod执行成功时调用)和一个异常处理函数(此函数在出现异常时被调用)。假如我们在后台增加一个GetData()并标记为[WebMethod],则前台的javascript在调用的方式为:PageMethods.GetData(SuccessHandler, ExceptionHandler)。为了便于理解,我为成功和异常处理函数起了一个适当的名称。当然你可以给它们起一个你喜欢的名字。如果PageMethod方法带有参数,你可以像这样调用它:PageMethods.GetData(param1, param2, SuccessHandler, ExceptionHandler)。
通过PageMethods调用的方法必须标记[WebMethod]并且必须是静态的方法。声明如下:
[WebMethod]
public static string GetData()
public static string GetData()
代码
MyEntity实体类public partial class AJAXGrid : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
[WebMethod]
public static IEnumerable<MyEntity> GetData()
{
try
{
Data fetch part should go here
// used List, as collections are serializable. See below for MyEntity class
List<MyEntity> MyEntities = new List<MyEntity>();
MyEntities.Add("1", "abc");
MyEntities.Add("2", "xyz");
MyEntities.Add("3", "pqr");
MyEntities.Add("4", "mno");
return MyEntities;
}
catch(Exception ex)
{
throw ex;
}
}
}
{
protected void Page_Load(object sender, EventArgs e)
{
}
[WebMethod]
public static IEnumerable<MyEntity> GetData()
{
try
{
Data fetch part should go here
// used List, as collections are serializable. See below for MyEntity class
List<MyEntity> MyEntities = new List<MyEntity>();
MyEntities.Add("1", "abc");
MyEntities.Add("2", "xyz");
MyEntities.Add("3", "pqr");
MyEntities.Add("4", "mno");
return MyEntities;
}
catch(Exception ex)
{
throw ex;
}
}
}
代码
public class MyEntity
{
private string _Column1;
public string Column1
{
get { return _Column1; }
set { _Column1 = value; }
}
private string _Column2;
public string Column2
{
get { return _Column2; }
set { _Column2 = value; }
}
public MyEntity(string sCol1, string sCol2)
{
_Column1 = sCol1;
_Column2 = sCol2;
}
}
{
private string _Column1;
public string Column1
{
get { return _Column1; }
set { _Column1 = value; }
}
private string _Column2;
public string Column2
{
get { return _Column2; }
set { _Column2 = value; }
}
public MyEntity(string sCol1, string sCol2)
{
_Column1 = sCol1;
_Column2 = sCol2;
}
}
用来调用后台的方法并填充HTML表格的javascript函数
代码
<script type ="text/javascript" language = "javascript ">
//Loading Data
// Handles btn_load click event
function LoadData() {
// If data was fetched successfully, SuccessHandler will be called; else, ExceptionHandler
PageMethods.GetData(SuccessHandler, ExceptionHandler);
// Incase parameters need to be passed to PageMethods, you can do like this PageMethods.GetData(param1, param2, SuccessHandler, ExceptionHandler)
}
// After fetching the data successfully
function SuccessHandler(result) {
var tbody = $get("tbody_grid");
// clear the table
for (var j = tbody.rows.length; j > 0; j--) {
tbody.deleteRow(j - 1);
}
// populate the table
for (var i = 0; i < result.length; i++) {
//two columns fetched from database are sent as parameters
AddRow(result[i].Column1, result[i].Column2);
}
return true;
}
// Edit and Delete buttons are added to the rows
function AddRow(col1, col2) {
var tbody = $get("tbody_grid");
var row = document.createElement("tr")
var td1 = document.createElement("td")
td1.innerText = col1;
var td2 = document.createElement("td");
td2.innerText = col2;
var td3 = document.createElement("td");
// add buttons
var btnEdit = document.createElement('input');
btnEdit.setAttribute('type', 'button');
btnEdit.setAttribute('name', 'Edit');
btnEdit.setAttribute('value', 'Edit');
// first parentNode represents <td> and the second represents <tr>
btnEdit.onclick = function() { Edit(this.parentNode.parentNode); };
var btnDelete = document.createElement('input');
btnDelete.setAttribute('type', 'button');
btnDelete.setAttribute('name', 'Delete');
btnDelete.setAttribute('value', 'Delete');
btnDelete.onclick = function() { DeleteRow(this.parentNode.parentNode); };
td3.appendChild(btnEdit);
td3.appendChild(btnDelete);
row.appendChild(td1);
row.appendChild(td2);
row.appendChild(td3);
tbody.appendChild(row);
}
// Handles exception
function ExceptionHandler(result) {
}
//Loading Data
// Handles btn_load click event
function LoadData() {
// If data was fetched successfully, SuccessHandler will be called; else, ExceptionHandler
PageMethods.GetData(SuccessHandler, ExceptionHandler);
// Incase parameters need to be passed to PageMethods, you can do like this PageMethods.GetData(param1, param2, SuccessHandler, ExceptionHandler)
}
// After fetching the data successfully
function SuccessHandler(result) {
var tbody = $get("tbody_grid");
// clear the table
for (var j = tbody.rows.length; j > 0; j--) {
tbody.deleteRow(j - 1);
}
// populate the table
for (var i = 0; i < result.length; i++) {
//two columns fetched from database are sent as parameters
AddRow(result[i].Column1, result[i].Column2);
}
return true;
}
// Edit and Delete buttons are added to the rows
function AddRow(col1, col2) {
var tbody = $get("tbody_grid");
var row = document.createElement("tr")
var td1 = document.createElement("td")
td1.innerText = col1;
var td2 = document.createElement("td");
td2.innerText = col2;
var td3 = document.createElement("td");
// add buttons
var btnEdit = document.createElement('input');
btnEdit.setAttribute('type', 'button');
btnEdit.setAttribute('name', 'Edit');
btnEdit.setAttribute('value', 'Edit');
// first parentNode represents <td> and the second represents <tr>
btnEdit.onclick = function() { Edit(this.parentNode.parentNode); };
var btnDelete = document.createElement('input');
btnDelete.setAttribute('type', 'button');
btnDelete.setAttribute('name', 'Delete');
btnDelete.setAttribute('value', 'Delete');
btnDelete.onclick = function() { DeleteRow(this.parentNode.parentNode); };
td3.appendChild(btnEdit);
td3.appendChild(btnDelete);
row.appendChild(td1);
row.appendChild(td2);
row.appendChild(td3);
tbody.appendChild(row);
}
// Handles exception
function ExceptionHandler(result) {
}
填充数据后的截图:
用来实现增删查改的javascript函数
编辑数据
代码
单击Edit按钮后的截图:// this function handles edit button click
function Edit(row) {
var col1 = row.childNodes[0].innerText;
var col2 = row.childNodes[1].innerText;
// populates values in textboxes and displays Update and Cancel buttons
var editableRow = document.createElement("tr")
var td1 = document.createElement("td")
var txtBox1 = document.createElement('input');
txtBox1.setAttribute('type', 'text');
txtBox1.setAttribute('name', 'col1');
txtBox1.setAttribute('value', col1);
txtBox1.setAttribute('width', 30);
td1.appendChild(txtBox1);
var td2 = document.createElement("td");
var txtBox2 = document.createElement('input');
txtBox2.setAttribute('width', 300);
txtBox2.setAttribute('type', 'text');
txtBox2.setAttribute('name', 'col1');
txtBox2.setAttribute('value', col2);
td2.appendChild(txtBox2);
var td3 = document.createElement("td");
var btnUpdate = document.createElement('input');
btnUpdate.setAttribute('type', 'button');
btnUpdate.setAttribute('name', 'Update');
btnUpdate.setAttribute('value', 'Update');
btnUpdate.onclick = function() { Update(this.parentNode.parentNode); };
var btnCancel = document.createElement('input');
btnCancel.setAttribute('type', 'button');
btnCancel.setAttribute('name', 'Cancel');
btnCancel.setAttribute('value', 'Cancel');
btnCancel.onclick = function() { Cancel(this.parentNode.parentNode); };
td3.appendChild(btnUpdate);
td3.appendChild(btnCancel);
editableRow.appendChild(td1);
editableRow.appendChild(td2);
editableRow.appendChild(td3);
row.parentNode.replaceChild(editableRow, row);
}
function Edit(row) {
var col1 = row.childNodes[0].innerText;
var col2 = row.childNodes[1].innerText;
// populates values in textboxes and displays Update and Cancel buttons
var editableRow = document.createElement("tr")
var td1 = document.createElement("td")
var txtBox1 = document.createElement('input');
txtBox1.setAttribute('type', 'text');
txtBox1.setAttribute('name', 'col1');
txtBox1.setAttribute('value', col1);
txtBox1.setAttribute('width', 30);
td1.appendChild(txtBox1);
var td2 = document.createElement("td");
var txtBox2 = document.createElement('input');
txtBox2.setAttribute('width', 300);
txtBox2.setAttribute('type', 'text');
txtBox2.setAttribute('name', 'col1');
txtBox2.setAttribute('value', col2);
td2.appendChild(txtBox2);
var td3 = document.createElement("td");
var btnUpdate = document.createElement('input');
btnUpdate.setAttribute('type', 'button');
btnUpdate.setAttribute('name', 'Update');
btnUpdate.setAttribute('value', 'Update');
btnUpdate.onclick = function() { Update(this.parentNode.parentNode); };
var btnCancel = document.createElement('input');
btnCancel.setAttribute('type', 'button');
btnCancel.setAttribute('name', 'Cancel');
btnCancel.setAttribute('value', 'Cancel');
btnCancel.onclick = function() { Cancel(this.parentNode.parentNode); };
td3.appendChild(btnUpdate);
td3.appendChild(btnCancel);
editableRow.appendChild(td1);
editableRow.appendChild(td2);
editableRow.appendChild(td3);
row.parentNode.replaceChild(editableRow, row);
}
更新数据
代码
// this function handles update button click
function Update(row) {
// fetches values entered in the textboxes
// first childNode represent <td> inside <tr> and second childNode represents textbox
var col1 = row.childNodes[0].childNodes[0].value;
var col2 = row.childNodes[1].childNodes[0].value;
// values sent to server
PageMethods.UpdateData(col1, col2, UpdateSuccess(row), ExceptionHandler);
}
// After updating the values successfully
function UpdateSuccess(row) {
var col1 = row.childNodes[0].childNodes[0].value;
var col2 = row.childNodes[1].childNodes[0].value;
var editableRow = document.createElement("tr")
var td1 = document.createElement("td")
td1.innerText = col1;
var td2 = document.createElement("td");
td2.innerText = col2;
var td3 = document.createElement("td");
var btnEdit = document.createElement('input');
btnEdit.setAttribute('type', 'button');
btnEdit.setAttribute('name', 'Edit');
btnEdit.setAttribute('value', 'Edit');
btnEdit.onclick = function() { Edit(this.parentNode.parentNode); };
var btnDelete = document.createElement('input');
btnDelete.setAttribute('type', 'button');
btnDelete.setAttribute('name', 'Delete');
btnDelete.setAttribute('value', 'Delete');
btnDelete.onclick = function() { DeleteRow(this.parentNode.parentNode); };
td3.appendChild(btnEdit);
td3.appendChild(btnDelete);
editableRow.appendChild(td1);
editableRow.appendChild(td2);
editableRow.appendChild(td3);
row.parentNode.replaceChild(editableRow, row);
}
// this function handles cancel button click
function Cancel(row) {
// values are again populated in labels instead of textboxes
var col1 = row.childNodes[0].childNodes[0].value;
var col2 = row.childNodes[1].childNodes[0].value;
var editableRow = document.createElement("tr")
var td1 = document.createElement("td")
td1.innerText = col1;
var td2 = document.createElement("td");
td2.innerText = col2;
var td3 = document.createElement("td");
var btnEdit = document.createElement('input');
btnEdit.setAttribute('type', 'button');
btnEdit.setAttribute('name', 'Edit');
btnEdit.setAttribute('value', 'Edit');
btnEdit.onclick = function() { Edit(this.parentNode.parentNode); };
var btnDelete = document.createElement('input');
btnDelete.setAttribute('type', 'button');
btnDelete.setAttribute('name', 'Delete');
btnDelete.setAttribute('value', 'Delete');
btnDelete.onclick = function() { DeleteRow(this.parentNode.parentNode); };
td3.appendChild(btnEdit);
td3.appendChild(btnDelete);
editableRow.appendChild(td1);
editableRow.appendChild(td2);
editableRow.appendChild(td3);
row.parentNode.replaceChild(editableRow, row);
}
// this function handles 'add' button click
function Add() {
var col1 = $get("txt_addcol1").value;
var col2 = $get("txt_addcol2").value;
// data sent to the database
PageMethods.InsertData(col1, col2, AddSuccess(col1, col2), ExceptionHandler);
}
// After adding the data successfully
function AddSuccess(col1, col2) {
// add the values to the table
AddRow(col1, col2);
// clear the textboxes in the footer
$get("txt_addcol1").value = "";
$get("txt_addcol2").value = "";
}
function Update(row) {
// fetches values entered in the textboxes
// first childNode represent <td> inside <tr> and second childNode represents textbox
var col1 = row.childNodes[0].childNodes[0].value;
var col2 = row.childNodes[1].childNodes[0].value;
// values sent to server
PageMethods.UpdateData(col1, col2, UpdateSuccess(row), ExceptionHandler);
}
// After updating the values successfully
function UpdateSuccess(row) {
var col1 = row.childNodes[0].childNodes[0].value;
var col2 = row.childNodes[1].childNodes[0].value;
var editableRow = document.createElement("tr")
var td1 = document.createElement("td")
td1.innerText = col1;
var td2 = document.createElement("td");
td2.innerText = col2;
var td3 = document.createElement("td");
var btnEdit = document.createElement('input');
btnEdit.setAttribute('type', 'button');
btnEdit.setAttribute('name', 'Edit');
btnEdit.setAttribute('value', 'Edit');
btnEdit.onclick = function() { Edit(this.parentNode.parentNode); };
var btnDelete = document.createElement('input');
btnDelete.setAttribute('type', 'button');
btnDelete.setAttribute('name', 'Delete');
btnDelete.setAttribute('value', 'Delete');
btnDelete.onclick = function() { DeleteRow(this.parentNode.parentNode); };
td3.appendChild(btnEdit);
td3.appendChild(btnDelete);
editableRow.appendChild(td1);
editableRow.appendChild(td2);
editableRow.appendChild(td3);
row.parentNode.replaceChild(editableRow, row);
}
// this function handles cancel button click
function Cancel(row) {
// values are again populated in labels instead of textboxes
var col1 = row.childNodes[0].childNodes[0].value;
var col2 = row.childNodes[1].childNodes[0].value;
var editableRow = document.createElement("tr")
var td1 = document.createElement("td")
td1.innerText = col1;
var td2 = document.createElement("td");
td2.innerText = col2;
var td3 = document.createElement("td");
var btnEdit = document.createElement('input');
btnEdit.setAttribute('type', 'button');
btnEdit.setAttribute('name', 'Edit');
btnEdit.setAttribute('value', 'Edit');
btnEdit.onclick = function() { Edit(this.parentNode.parentNode); };
var btnDelete = document.createElement('input');
btnDelete.setAttribute('type', 'button');
btnDelete.setAttribute('name', 'Delete');
btnDelete.setAttribute('value', 'Delete');
btnDelete.onclick = function() { DeleteRow(this.parentNode.parentNode); };
td3.appendChild(btnEdit);
td3.appendChild(btnDelete);
editableRow.appendChild(td1);
editableRow.appendChild(td2);
editableRow.appendChild(td3);
row.parentNode.replaceChild(editableRow, row);
}
// this function handles 'add' button click
function Add() {
var col1 = $get("txt_addcol1").value;
var col2 = $get("txt_addcol2").value;
// data sent to the database
PageMethods.InsertData(col1, col2, AddSuccess(col1, col2), ExceptionHandler);
}
// After adding the data successfully
function AddSuccess(col1, col2) {
// add the values to the table
AddRow(col1, col2);
// clear the textboxes in the footer
$get("txt_addcol1").value = "";
$get("txt_addcol2").value = "";
}
删除数据
代码
// this function handles delete button click
function DeleteRow(row) {
var col1 = row.childNodes[0].innerText;
// delete from the database
PageMethods.DeleteData(col1, DeleteSuccess(row), ExceptionHandler);
}
function DeleteSuccess(row) {
// delete the row from the table
var tbody = $get("tbody_grid");
tbody.removeChild(row);
}
</script>
function DeleteRow(row) {
var col1 = row.childNodes[0].innerText;
// delete from the database
PageMethods.DeleteData(col1, DeleteSuccess(row), ExceptionHandler);
}
function DeleteSuccess(row) {
// delete the row from the table
var tbody = $get("tbody_grid");
tbody.removeChild(row);
}
</script>
处理增删查改的PageMethod方法
代码
[WebMethod]
public static void UpdateData(string sCol1, string sCol2)
{
try
{
Data update part should go here
}
catch(Exception ex)
{
throw ex;
}
}
[WebMethod]
public static void InsertData(string sCol1, string sCol2)
{
try
{
Data insert part should go here
}
catch(Exception ex)
{
throw ex;
}
}
[WebMethod]
public static void DeleteData(string sCol1)
{
try
{
Data delete part should go here
}
catch (Exception ex)
{
throw ex;
}
}
}
public static void UpdateData(string sCol1, string sCol2)
{
try
{
Data update part should go here
}
catch(Exception ex)
{
throw ex;
}
}
[WebMethod]
public static void InsertData(string sCol1, string sCol2)
{
try
{
Data insert part should go here
}
catch(Exception ex)
{
throw ex;
}
}
[WebMethod]
public static void DeleteData(string sCol1)
{
try
{
Data delete part should go here
}
catch (Exception ex)
{
throw ex;
}
}
}
还可以为其增加分页及排序功能。
代码在IE7+,Firefox,Chrome和Safari中测试成功。使用ASP.NET AJAX的PageMethods方法的一些限制:
1.在[WebMethod]标记的方法中不能直接访问服务端控件(如textbox)
2.不能访问后台代码中声明的任何变量