ASP.NET 结合基于表单的 CRUD 数据库操作的 Dojo 实用入门指南
ASP.NET 结合基于表单的 CRUD 数据库操作的 Dojo 实用入门指南
概述
在本指南中,我将向您展示如何使用 Dojo 的数据网格来创建用于数据库 CRUD(创建、读取、更新、删除)操作的基于 Web 的表单。数据编辑在弹出窗口中进行,而不是直接在网格中。数据网格表单支持键盘导航(光标键、Enter 键用于编辑、Delete 键用于删除记录以及 F2 键用于添加新记录)。本文基于我在使用 Dojo 实现基于 Web 的 CRUD 系统时学到的知识。可能有些地方是我的错误或误解,因此如果您发现任何错误或有建议,请随时与我联系。
在 **“使用代码”** 部分,您将了解如何在不到 90 分钟的时间内使用此代码来实现一个简单的公司电话列表应用程序。
它看起来会是这样的
这是编辑记录的屏幕截图
下载通用入门指南的 Visual Web Developer Express 2010 解决方案
引言
作为程序员,您经常会面临为具有不同计算机经验水平的用户创建数据编辑表单的任务。几乎所有用户都能上网,因此使用基于 Web 的系统而不是桌面应用程序非常普遍,尤其是在商业环境中。
本文将向您展示如何使用 Dojo JavaScript 框架构建一个简单的数据创建/读取/更新/删除(CRUD)表单。
背景
我一直在寻找一种方法来创建基于 Web 的(IIS 上的 ASPX)CRUD 数据库操作表单。
框架的关键要求
我有四个关键要求
- 数据应以某种形式的数据网格显示,并支持键盘导航
- 保存/删除项目时,操作不应生成完全的页面回发
- 编辑应在弹出窗口中进行。也可以进行内联编辑
- 使用的框架应具有开放许可证,因此可以免费使用
在评估的框架列表中,我几乎包含了所有免费框架(JavaScript 或 ASPX)。
默认 aspx 控件中的网格控件并不是我想要的。主要缺失的功能是键盘导航。另一个缺点是,用户对默认网格控件的体验远不如桌面网格。
我评估了几款适用于 JQuery 的网格控件,并注意到每个网格都有其优缺点。我没有找到一个能为我完成所有任务的控件,尤其是内联编辑似乎是一个巨大的问题。
DHTMLX 几乎是完美的工具包,它在客户端运行,拥有数十种控件,非常成熟,并且有一个健康的论坛。唯一不好的是它的许可证。对于 GPL 项目它是免费的,但我不能一直这样。如果您有预算,可以尝试一下,它几乎拥有您正常操作所需的所有基本功能,并且非常易于定制,您不会后悔的。
Dojo 是一个在客户端运行的 JavaScript 工具包,它具有我想要的所有功能,并且额外提供了许多其他控件。它的许可证是:“Academic Free License >= 2.1 或修改后的 BSD 许可证”,这对于我的用例来说绰绰有余。 它似乎非常成熟,但文档略有不足。在线文档还可以,但没有关于 Dojo 最新版本的书籍。我做了一些原型,涵盖了内联编辑和弹出窗口编辑。本文侧重于弹出窗口编辑。
Dojo 有三个主要对象:**dojo**(具有通用方法)、dijit(用户界面对象)和 **dojox**(涵盖网格和图表等附加的 dojo 项目)。(本文是关于 dojox.grid)在您的 html/aspx 页面中引用 dojo
Dojo 需要与它的样式文件一起引用到您 html 文件的 head 标签中。
默认的 CSS 样式名为 **claro**。使用 Dojo 不需要其他引用。所需的模块稍后定义,并由 Dojo 内部加载。这使得 Dojo 与其他 JavaScript 框架非常不同,在那些框架中,您需要包含您使用的所有模块的 .js 文件。
构建用户界面
在 Dojo 中,您可以通过类似 html 的标签构建 UI,或者在运行时创建 JavaScript 对象。我选择在 JavaScript 中创建网格和工具栏,并仅添加了几个 div 和一个 span 作为控件的占位符。
我在屏幕顶部放置了一个额外的工具栏,上面有“添加”、“编辑”和“删除”记录的按钮。
(工具栏对象在 dijit/Toolbar 中定义)
用户操作数据的弹出窗口是作为一个 Dojo dijit/Dialog 对象实现的,它显示一个单独的 aspx 页面,该页面处理将数据添加到数据库的代码,并在保存成功或失败时调用 JavaScript 函数。
将数据加载到网格中
Dojo 为需要绑定到控件的数据提供了一个抽象层,使用 dojo.data 中的对象,取决于它是可写的还是只读的。这个抽象层能够处理分页、按需加载以及其他许多功能。在我看来,大多数情况下记录数量在几十到几百之间,所以我决定在页面加载时加载所有记录并进行处理。由于我们使用 AJAX 回调,无需重新加载整个页面,因此从性能上看是可行的。但是,如果您期望处理大量数据,请查阅文档中的 dojo.data 部分。
本示例包含一个小型 SqlCE 数据库,名为 Customers.sdf(位于 App_Data 文件夹中),其中包含一个客户表。在“*页面加载*”事件上,会获取所有记录并将其注入到 JavaScript 代码中。
对数据进行排序
Dojo 的网格支持通过单击表头列进行排序,这与其他几乎所有网格控件一样。排序是在客户端完成的,但默认情况下是区分大小写的,这非常少见。这意味着您会在顶部看到大写的 **A 到 Z**,然后是小写的 **a 到 z**。为了使排序行为符合预期顺序,必须在数据存储(而不是网格)级别实现自定义比较器。
摆脱网格中的鼠标悬停效果
网格控件的 CSS 样式定义了一个鼠标悬停条,看起来很漂亮,但在我的场景中不起作用(不是技术上的问题,而是会干扰用户识别当前选中的行)。我尝试过动态和静态地覆盖 aspx 页面中的样式,但都没有成功。最后,我直接编辑了 CSS 文件“claroGrid.css”来隐藏鼠标悬停条。
键盘导航
网格在获得焦点后支持使用光标键进行行选择。我添加了额外的事件处理程序来捕获 Enter 键以打开编辑弹出窗口。在 dojo 中,这是通过使用 dojo.connect 函数完成的。
删除记录
数据库级别的删除过程在一个单独的 aspx 页面中完成,该页面通过 id URL 参数提供记录 ID。该页面通过 JSONP 调用,并报告其结果为“OK:”或显示给用户的其他通知。这也可以实现到编辑记录页面,但我选择将其分开以使代码更易读。
数据库连接
我为这个项目使用了“SQL Server Compact Edition”数据库文件。如果您在访问它时遇到问题,请检查您是否已将 3.5 版本安装到您的服务器/开发机器上。
我将在下面的参考部分提供下载链接。
我必须在 global.asax 中添加代码才能使数据库文件可被 ASP.NET 访问。
有趣的代码片段(按源代码出现顺序)
我将在本节中解释重要或有趣的代码片段。
变量
我在我的 JavaScript 中声明了这个全局变量
var deleteUrl = "./services/DeleteCustomer.aspx";
var editUrl = "./services/EditCustomer.aspx";
var gridColumns = [ // name is the column name, field is the fieldname in the store
{ name: "ID", field: "CustomerID", width: "50px" },
{ name: "CompanyName", field: "CompanyName", width: "auto", editable: false },
{ name: "ContactTitle", field: "ContactTitle", width: "auto", editable: false },
{ name: "ContactName", field: "ContactName", width: "auto", editable: false },
{ name: "Address", field: "Address", width: "auto", editable: false },
{ name: "City", field: "City", width: "auto", editable: false },
] ;
var idColumnName = "CustomerID";
var defaultSortField = "CompanyName";
var defaultSortDescending = false;
var caseInsitiveSortedColumns =["CompanyName","ContactTitle"...]; // !*** Add columns that should be sorted case insensitive here !
var popUpDialogWidth = "600px"; // Height of the popup Dialog
var popUpDialogHeight = "380px"; // Width of the popup Dialog
var popUpDialogIframeWidth = "100%"; // It's not necessary to adjust this
var popUpDialogIframeHeight = "330px"; // Adjust this if you change the Dialogs height
var gridData= <%=Daten%>
**deletUrl** 和 **editUrl** 是指向用作数据服务的网页的 URL 地址。
**gridColumns** 数组定义了数据存储和网格布局。此数组中的可能选项
- name -> 网格标题行中显示的列标题
- field -> 由注入的 JavaScript(参见 customer.aspx.cs)提供的数据字段的名称
- width -> 列的宽度(可能的值:50px,auto)
- editable -> 指示单元格的值在网格中是否可编辑(本项目为 false)
**idColumnName** 获取所有服务中使用的 ID 数据字段的名称。(该字段在所有服务 aspx 文件中必须相同!)
**defaultSortField** 获取加载后用于网格中默认排序的数据字段的名称,变量 **defaultSortDescending** 指示排序方向。
如前所述,Dojo 默认对网格值进行区分大小写的排序。所有需要不区分大小写排序的列都必须在其显示名称中添加到 **caseInsensitiveSortedColumns** 数组。
加载 Dojo 模块
Dojo 模块的加载将使用 Dojo 提供的 **require** 方法完成,该方法将自动创建模块对象实例,并在紧随模块加载后调用的函数中可用,该函数可用于初始化。
require([ "dojox/grid/DataGrid",
"dojo/data/ItemFileWriteStore",
"dojo/date/locale",
"dojo/_base/lang",
"dijit/form/HorizontalSlider",
"dojox/grid/cells/dijit",
"dojox/grid/Selection",
"dojo/store/JsonRest",
"dojo/store/Memory",
"dojo/store/Cache",
"dojo/data/ObjectStore",
"dojo/query",
"dijit/Toolbar",
"dijit/form/Button",
"dojo/_base/array",
"dojo/parser",
"dijit/layout/ContentPane",
"dijit/layout/BorderContainer",
"dijit/Dialog",
'dojo/data/ItemFileWriteStore',
'dojo/io/script'
],
function ( DataGrid,
ItemFileWriteStore,
locale,
lang,
HorizontalSlider,
Cells_dijit,
Selection,
JsonRest,
Memory,
Cache,
ObjectStore,
query,
Toolbar,
Button,
array,
parser,
cContentPane,
borderContainer,
dialog,
ItemFileWriteStore,
Script)
{ .... });
请注意,生成的对象的名称在函数参数中定义。
创建工具栏
使用以下代码创建工具栏,可以通过向 **buttonDefinition** 数组添加新按钮来轻松扩展
// Create the toolbar buttons based on the definition in this array // format: id, label, image var buttonDefinition = [ ["new", "New", "NewPage"], ["edit", "Edit", "Copy"], ["delete", "Delete", "Delete"] ]; toolbar = new Toolbar({}, "toolbar"); // The last parameter defines the span tag that takes the toolbar array.forEach(buttonDefinition, function (but) { var button = new Button( { // Note: The Dojo docu says buttons should always specify a label for accessibility reasons. // To hide the label just set showLabel:false label: but[1], showLabel: true, iconClass: "dijitEditorIcon dijitEditorIcon" + but[2], id: but[0], onClick: toolbarButtonClick }); toolbar.addChild(button); });
按钮的图像由 Dojo 框架提供,无需额外的图像文件,它们已包含在 Dojo 框架中。
为网格创建数据存储
网格的数据存储仅使用一行代码创建,使用由 aspx.cs 文件获取并作为 JavaScript 数组注入到全局变量 gridData 中的数据。
gridStore = new ItemFileWriteStore({ data: gridData });
使列排序不区分大小写
要使列排序不区分大小写,需要两项内容
- 网格存储的比较器映射
- 比较器函数本身
使用此代码设置 comparatorMap
// Create the case insensitive columns comparator
gridStore.comparatorMap={};
array.forEach(caseInsitiveSortedColumns, function (colName)
{
gridStore.comparatorMap[colName] = caseInsensitiveComparator;
});
内部函数循环遍历需要不区分大小写排序的列名列表,并为该列向 comparatorMap 添加一个比较器。
比较器的实现会比较两个值,并根据比较返回小于、等于或大于零的数值。
function caseInsensitiveComparator (a,b) { if (a.toLowerCase() < b.toLowerCase()) { return -1 } else if (a.toLowerCase() > b.toLowerCase()) { return 1; } else { return 0; } }
最重要的一点是,在比较之前,字符串将被**转换为小写**。
创建网格(最终)
通过实例化一个新的 DataGrid 对象来创建网格,并定义网格应添加到哪个 html div 标签:grid = new DataGrid( { "class": "grid", rowsPerPage: "10000", width: "auto", store: dataStore = gridStore, sortFields:[{attribute:defaultSortField,descending: defaultSortDescending}], structure: gridColumns // The column setup }, "grid"); // grid is the HTML div tag where we create the grid in
参数不言自明,唯一需要注意的是 store 赋值,我们在这里分配之前生成的 store 对象,以及 structure 赋值,它从名为 **gridColumns** 的全局变量数组中获取数据。
添加键盘事件处理程序
Dojo 中的事件处理程序使用 **dojo.connect** 方法添加到控件。我添加了 Enter 键、Delete 键和 F2 键的处理程序。
dojo.connect(grid, "onKeyPress", function (e) { switch(e.charOrCode) { case dojo.keys.ENTER: { ... break; } case dojo.keys.DELETE: { ... break; } case dojo.keys.F2: { ... break; } } });
使用代码
在本节中,我将通过创建一个简单的公司内部网电话列表来展示如何使用此代码,该列表存储员工姓名、姓氏、办公室号码和内部电话号码。
所需文件
要实现此代码,您需要下载 zip 文件“Dojo-CRUD-Sample.zip”并将其解压缩到您的文件系统中。(或者,您可以下载“CompanyPhoneList.zip”,其中包含完整的“Microsoft Visual Web Developer 2010 express”解决方案。
以下步骤假设您使用的是“Dojo-CRUD-Sample.zip”)。
准备项目
在 Visual Studio 或 Visual Web Developer 中创建一个名为 CompanyPhoneList 的新空白项目。编程语言选择应设置为 C#。(在 Visual Studio 2010 中,您应该选择“Empty ASP.NET Web Application”)。
将下载并解压缩的 zip 文件中的 dojo 文件夹通过拖放到解决方案资源管理器中,并将其放在项目名称上。(如果您使用 Visual Studio 而不是 Visual Web Developer,请确保将其放在项目上,而不是解决方案上。在 Visual Studio 中,您的解决方案可能包含多个项目)。
对 css 文件夹执行相同的操作,以获取页面的样式表信息。右键单击解决方案资源管理器中的项目,然后选择“添加”->“ASP.NET 文件夹”->“App_Data”。
此文件夹将保存我们用作数据库的 XML 文件,名为 PhoneList.xml。
再次右键单击解决方案资源管理器中的项目,然后单击“添加”->“新建文件夹”并命名为“services”。
添加三个额外的网站,一个用于电话列表,一个用于数据编辑服务,第三个用于记录删除服务。理论上,这两个服务功能可以实现在一个页面中,但我更喜欢分开。 我们需要这些文件:
名称 |
Location |
目的 |
CompanyPhoneList.aspx |
/ |
主电话列表页面 |
CompanyPhoneList_Edit.aspx |
/services/ |
保存编辑/新记录 |
CompanyPhoneList_Delete.aspx |
/services/ |
删除记录 |
您的解决方案现在应该看起来像这样(您的结果可能因您的 Windows/VS/VWD 语言而略有不同,我的语言是德语)。
您可能想右键单击“CompanyPhoneList.aspx”文件并选择“设为启动页”。
CompanyPhoneList.aspx
在 CompanyPhoneList.aspx.cs 文件中,我们开始实现所需的数据库访问功能。内部我们使用一个存储在 App_Data 文件夹中的 DataTable(已序列化)。如果文件不存在,页面将创建一个新的空数据库。
将类定义以外的所有源代码替换为以下代码(覆盖任何现有的 PageLoad 事件处理程序):
public string dataInJsArrayFormat = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
DataTable dtData;
string databaseFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\PhoneList.xml");
try
{
if (!Page.IsPostBack)
{
if (File.Exists(databaseFileName))
{ // Load existing database
dtData = new DataTable();
dtData.ReadXml(databaseFileName);
}
else
{ // Create new database
dtData = new DataTable("PhoneList");
dtData.Columns.Add(new DataColumn("id", typeof(Int32)));
dtData.Columns[0].AutoIncrement = true;
dtData.Columns[0].AutoIncrementSeed = 1;
dtData.Columns[0].AutoIncrementStep = 1;
dtData.Columns.Add(new DataColumn("name", typeof(String)));
dtData.Columns.Add(new DataColumn("surname", typeof(String)));
dtData.Columns.Add(new DataColumn("officeNo", typeof(String)));
dtData.Columns.Add(new DataColumn("phoneNo", typeof(String)));
dtData.WriteXml(databaseFileName, XmlWriteMode.WriteSchema);
}
// Database is existing now, read it and response as JS array
StringBuilder sbResult = new StringBuilder();
int rowCounterExported = 0;
foreach (DataRow dr in dtData.Rows)
{
rowCounterExported++;
if (rowCounterExported > 1)
sbResult.Append(",");
sbResult.Append("{" + enq("id") + ":" + enq(dr["id"].ToString()) + ",");
sbResult.Append(enq("name") + ":" + enq(dr["name"].ToString()) + ",");
sbResult.Append(enq("surname") + ":" + enq(dr["surname"].ToString()) + ",");
sbResult.Append(enq("officeNo") + ":" + enq(dr["officeNo"].ToString()) + ",");
sbResult.Append(enq("phoneNo") + ":" + enq(dr["phoneNo"].ToString()) );
sbResult.Append("}");
}
string resultText = " { identifier: 'id', label: 'CompanyPhoneList', items:[";
resultText += sbResult.ToString();
resultText += "]}";
dataInJsArrayFormat = resultText;
}
}
catch (Exception eX)
{
Response.Write("Error:" + eX.Message);
}
}
// Enquotes a given String and encodes the new lines and encodes the quotes as well as double quotes
private string enq(string txt)
{
string result = txt.Replace("\"", "\\\"");
result = result.Replace("\'", "\\\'");
result = result.Replace("\n", "\\\n");
result = result.Replace("\r", "\\\r");
return "\"" + result + "\"";
}
源代码相当直接且易于理解。 它所做的只是从 XML 文件加载或创建一个 ADO.NET DataTable。
让 IDE 修复所有未解析的引用以及正确的 using 语句。之后,构建应该没有任何错误。现在切换到源代码视图中的 CompanyPhoneList.aspx。
进行以下修改
- 在 <title> 标签中添加文本 CompanyPhoneList
- 更新服务 URL 的赋值
var deleteUrl = "./services/CompanyPhoneList_Delete.aspx";
var editUrl = "./services/CompanyPhoneList_Edit.aspx";
- 将 gridColumns 的赋值更改为:
var gridColumns = [
{ name: "Surname",field: "surname", width: "auto", editable: false },
{ name: "Name",field: "name", width: "auto", editable: false },
{ name: "Officeno", field: "officeNo",width: "auto", editable: false },
{ name: "Phone no", field: "phoneNo", width: "auto", editable: false}
]; 更新 idColumnName 的赋值
var idColumnName = "id";
- 更新默认排序字段的赋值
var defaultSortField = "Surname";
- 更新 caseInsitiveSortedColumns
var caseInsitiveSortedColumns =["surname","name","officeNo","phoneNo"]; - 将 gridData 的赋值更改为此值
var gridData= <%=dataInJsArrayFormat%>;
按下 Ctrl-F5 应该会构建并运行解决方案,如果一切顺利,会显示一个空网格。
CompanyPhoneList_Edit.aspx
将此 JavaScript 代码添加到编辑弹出窗口的 .aspx 页面的 head 元素中,这将使焦点设置到参数中的元素。
<script language="javascript" type="text/javascript">
function setFocusAndSelectText(elemntName)
{ //Set the focus and to the Company Name field and select it's content
document.getElementById(elemntName).focus();
document.getElementById(elemntName).select();
}
</script>
用此代码替换现有的 body 标签,该代码将聚焦并选择
姓氏文本框中的值。
<body onload="window.setTimeout('setFocusAndSelectText(\'tbSurname\');',200);">
从 form 标签中删除现有的 div 标签(如果 VS 创建了任何内容),并将以下标签添加到 form 标签中:
<asp:Panel runat="server" ID="pnSurname" GroupingText="Surname">
<asp:TextBox ID="tbSurname" runat="server" AutoComplete="Off" Width="95%"></asp:TextBox><asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="tbSurname" ErrorMessage=" *" ForeColor="Red" Font-Bold="true"></asp:RequiredFieldValidator>
</asp:Panel>
<asp:Panel runat="server" ID="pnName" GroupingText="Name"><asp:TextBox ID="tbName" runat="server" AutoComplete="Off" Width="95%"></asp:TextBox></asp:Panel>
<asp:Panel runat="server" ID="pnOfficeNo" GroupingText="Office no"><asp:TextBox ID="tbOfficeNo" runat="server" AutoComplete="Off" Width="95%"></asp:TextBox></asp:Panel>
<asp:Panel runat="server" ID="pnPhoneNo" GroupingText="Phone no"><asp:TextBox ID="tbPhoneNo" runat="server" AutoComplete="Off" Width="95%"></asp:TextBox></asp:Panel>
<asp:Panel ID="Panel1" runat="server" Width="100%" HorizontalAlign="Right">
<br />
<asp:Button ID="btSave" runat="server" Text="SAVE" onclick="btSave_Click" />
</asp:Panel>
这将向弹出窗口添加一个带有描述和输入字段的面板。
接下来,我们必须向 CompanyPhoneList_Edit.aspx.cs 文件添加代码。将此代码添加到自动生成的 Page_Load 事件中,它将加载应该编辑的记录。
DataTable dtData;
string databaseFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\PhoneList.xml");
try
{
string id2Edit = string.Empty;
try
{
id2Edit = Request.Params["id"].ToString();
}
catch { }
if ((!Page.IsPostBack) && (!String.IsNullOrEmpty(id2Edit)))
{
if (File.Exists(databaseFileName))
{ // Load existing database
dtData = new DataTable();
dtData.ReadXml(databaseFileName);
DataRow[] dr = dtData.Select("id = " + id2Edit);
if ((dr != null) && (dr.Length == 1))
{
tbName.Text = dr[0]["name"].ToString();
tbSurname.Text = dr[0]["surname"].ToString();
tbOfficeNo.Text = dr[0]["officeNo"].ToString();
tbPhoneNo.Text = dr[0]["phoneNo"].ToString();
}
else
{ // record not found
Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.closePopupAndShowError(\"Record not found, maybe already deleted!\");", true);
}
}
else
{
Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.closePopupAndShowError(\"Record not found, maybe already deleted!\");", true);
}
}
}
catch (Exception eX)
{
Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.closePopupAndShowError(\"Error:" + eX.Message + "\");", true);
}
这是实际保存过程的代码,需要插入到
Page_Load 事件下方
protected void btSave_Click(object sender, EventArgs e)
{
DataTable dtData;
string databaseFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\PhoneList.xml");
try
{
string id2Edit = string.Empty;
bool newRecordAdded = false;
try
{
id2Edit = Request.Params["id"].ToString();
}
catch { }
if (File.Exists(databaseFileName))
{ // Load existing database
dtData = new DataTable();
dtData.ReadXml(databaseFileName);
if (!String.IsNullOrEmpty(id2Edit))
{
DataRow[] dr = dtData.Select("id = " + id2Edit);
if ((dr != null) && (dr.Length == 1))
{
dr[0]["name"] = tbName.Text;
dr[0]["surname"] = tbSurname.Text;
dr[0]["officeNo"] = tbOfficeNo.Text;
dr[0]["phoneNo"] = tbPhoneNo.Text;
dtData.AcceptChanges();
}
else
{ // record not found
Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.closePopupAndShowError(\"Record not found, maybe already deleted!\");", true);
}
}
else
{ // Add new record
newRecordAdded = true;
DataRow drNew = dtData.NewRow();
drNew["name"] = tbName.Text;
drNew["surname"] = tbSurname.Text;
drNew["officeNo"] = tbOfficeNo.Text;
drNew["phoneNo"] = tbPhoneNo .Text;
dtData.Rows.Add(drNew);
dtData.AcceptChanges();
id2Edit = drNew["id"].ToString();
}
// Save the database file
dtData.WriteXml(databaseFileName, XmlWriteMode.WriteSchema);
// Database is writen to disk, create the JSON Javascript answer object (array) that transmits all entered values to the grids page to update the view
StringBuilder sb = new StringBuilder();
sb.Append("{ \"name\" : \"");
sb.Append(encodeJsonSpecialChars(tbName.Text));
sb.Append("\",\"surname\":\"");
sb.Append(encodeJsonSpecialChars(tbSurname.Text));
sb.Append("\",\"officeNo\":\"");
sb.Append(encodeJsonSpecialChars(tbOfficeNo.Text));
sb.Append("\",\"phoneNo\":\"");
sb.Append(encodeJsonSpecialChars(tbPhoneNo.Text));
sb.Append("\",\"id\":\"");
sb.Append(id2Edit.ToString());
sb.Append("\"}");
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "ret", "retVal=" + sb.ToString(), true);
if (newRecordAdded == true)
Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.newRecordSaved(retVal);", true);
else
Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.editedRecordSaved(retVal);", true);
}
else
{
Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.closePopupAndShowError(\"Database not found!\");", true);
}
}
catch (Exception eX)
{
Page.ClientScript.RegisterStartupScript(this.GetType(), "onLoad", "parent.closePopupAndShowError(\"Error:" + eX.Message + "\");", true);
}
}
还需要添加一个附加的辅助函数,这样我们就可以完成这个代码文件了。
(直接将其放在 btSave_Click 事件下方即可)
//Encodes the entered values to make it JSONP compatible
//An (well proved working) alternative is to use Newtonsofts Json.dll, but I don't want to bundle it with this
private string encodeJsonSpecialChars(string txt)
{
string result = txt.Replace("\"", "\\\"");
result = result.Replace("\'", "\\\'");
result = result.Replace("\n", "\\\n");
result = result.Replace("\r", "\\\r");
return result;
}
如果您构建项目并在浏览器中打开它,记录编辑和添加新记录都应该可以工作。请记住键盘快捷键:F2 用于新记录,Enter 用于编辑当前选定的记录。
CompanyPhoneList_Delete.aspx
在 .aspx 文件中,删除除第一行之外的所有行。这没关系,因为此页面仅响应 JSONP 请求。
切换到代码文件(CompanyPhoneList_Delete.aspx.cs)并将此代码添加到自动生成的 Page_Load 事件中,该代码执行实际的记录删除操作。
string resultText = string.Empty;
string callBackFuncName = string.Empty;
try
{
Response.Clear();
Response.ContentType = "text/javascript";
DataTable dtData = new DataTable();
string id2Delete = String.Empty;
string databaseFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\PhoneList.xml");
try
{
callBackFuncName = Request.Params["callback"].ToString();
}
catch { }
try
{
id2Delete = Request.Params["id"].ToString();
}
catch { }
if (!String.IsNullOrEmpty(id2Delete))
{
// Read the database file, remove the record and save it again
dtData.ReadXml(databaseFileName); // No further testing of existence needed
DataRow[] dr = dtData.Select("id = '" + id2Delete + "'");
if ((dr != null) && (dr.Length == 1))
{
dtData.Rows.Remove(dr[0]); // Remove the row
dtData.WriteXml(databaseFileName, XmlWriteMode.WriteSchema); // Write the file
resultText = "OK:";
}
else
throw new Exception("Record to delete not found !");
}
else
throw new Exception("Record to delete not specified!");
}
catch (Exception eX)
{
resultText = "Error:" + eX.Message;
}
Response.Write(callBackFuncName + " ('" + resultText + "');");
Response.End();
结论
使用 Dojo,您可以轻松地使用 Microsoft 的 ASP.NET 平台创建用于 CRUD 数据库操作的基于 Web 的表单。参考文献
Dojo 工具包的首页(2012-07-20 07:16):http://dojotoolkit.org/
Dojo 基金会的首页(2012-07-20 07:20):
http://dojofoundation.org/
SQL Server Compact Edition Version 3.5 可在此处下载(2012-07-20 07:16)
http://www.microsoft.com/de-de/download/details.aspx?id=5783
法律事宜
Microsoft、ASP.NET、Visual Studio 和 Visual Web Developer 是 Microsoft Corporation 在美国和其他国家的注册商标。 (http://www.microsoft.com)
我没有找到关于 Dojo 框架的任何商标信息。也许它被 Dojo 基金会注册了商标。如果是这样,这里会提到。
历史
20120720 初始发布