日期:2009-08-24  浏览次数:20514 次

注 与本文相关的下载文件的 Visual Basic_ 版本已于 3 月 4 日进行了更新。如果您是在 3 月 4 日之前下载源代码的,则将需要重新下载该文件以获得 Visual Basic 文件。




ASP.NET DataGrid 控件生成一个 HTML 输出结果,此结果看上去确实像 Microsoft Excel 工作表的 Web 副本。另外,该控件支持如选择和就地编辑之类的功能,这些功能又进一步证实了这种相似性。特别是,从支持就地编辑功能这一点来看时,这种相似性就最为明显了。当您单击特殊类型的命令列时,网格会使用文本框(而非静态文本)重绘其内容。与此同时,命令列会更改布局,将编辑链接替换为两个其他链接 — 一个用来保存所做的更改,另一个用来取消所做的更改。整个看上去几乎与 Excel 名称框命令栏完全相同。

DataGrid 还使程序员有机会在某种程度上自定义所编辑的单元格的布局。这可通过以下方法来实现:使用模板化列来代替绑定列和按钮列,并在模板化列的标记正文中定义编辑模板。

简单地说,DataGrid 控件只是为就地编辑提供基础结构,并在保存所做的更改时激发某些事件。为了能够完全编辑,网格组件应当提供三个您可能希望针对数据源执行的基本操作:“插入、“删除和 “更新”。DataGrid 用于编辑的基础结构(基本上是 EditCommandColumn 列类)只保证能够执行更新和删除操作。实现 “删除” 功能相对容易些,而且只要求您定义一个命令名为 “删除” 的 ButtonColumn 对象,并等待DeleteCommand 事件激发。

在本专栏中,您将看到如何扩展 DataGrid 控件,使其支持 INSERT 命令。我们将通过创建一个新类并让其从 DataGrid 继承来实现这一点。我们将使该类尽可能多地实现样本代码,以省去某些重复编码。因此,我们将拥有一个激发新事件和更具体事件的控件,而且我们可以使用这个唯一的界面来维护数据库表。

EditableGrid 控件

新控件应当具有哪种接口?

的思路是尽可能限制程序员必须编写的代码的数量。该控件将负责向其自身的接口中添加任何新行,然后在需要保存所做的更改时警告用户。这一原则适用于大多数操作,而不应当仅限于 “插入”。在实现就地编辑和删除时,总是必须在 SQL 语句周围放一些相对标准的和重复的代码。特别是在实现就地编辑功能时,必须重置所编辑项目的索引,并重新加载和重新绑定更新过的数据源。所有这些样本代码将嵌入到新的 EditableGrid 控件中。因此,该控件提供一个名为 AddNewRow 的新布尔属性,以及几个自定义事件 — InitRow、UpdateView、“保存数据”、“插入数据” 和 “删除数据”。

当用户希望添加新行时,他(或她)只需将 AddNewRow 属性设置为 true 并重新绑定该控件。该操作的其余部分在内部发生。(稍后我将描述此过程的细节。)新行将在编辑模式下绘制,InitRow 事件将激发,其目的只是使您有机会将某些字段设置为默认值。

UpdateView 的角色不与更新操作紧密相关。DataGrid 控件不缓存数据源,因此,无论页面何时回发(以便进行分页、排序、编辑、插入或删除),您都需要重新绑定。为了简化编码并尽可能多地嵌入编码,添加了这个新事件。当该网格需要设置其 DataSource 属性时,“更新视图” 就会激发。“更新视图” 的典型处理程序将当前的数据源分配给该属性并调用 DataBind 方法。

当相应的 SQL 语句不能进一步延迟执行时,就会激发其他三个事件 — “保存数据”、“插入数据” 和 “删除数据”。在处理其中的任何事件时,可设置和执行 “更新”、“插入” 或 “删除” 语句。您负责检索更新后的数据,并准备和执行该命令。除了 “插入数据”(与 DataGrid 编程接口没有紧密关系)以外,“保存数据” 和 “删除数据” 也不同于标准的 UpdateCommand 和 DeleteCommand,这是因为它们更具体而且只要求您执行 SQL 代码。新事件基本上由 UpdateCommand 和 DeleteCommand 的处理程序激发,这些处理程序是 EditableGrid 控件在加载时以静默方式定义的。这些内部处理程序负责执行所有其他任务(例如,重置索引)并刷新视图。后者(即刷新视图)是通过激发 UpdateView 事件来完成的。

设置控件

让我们快速浏览 EditableGrid 类。该类的构造函数初始化某些公共属性和受保护的属性,并为基类的几个事件设置默认处理程序。

namespace BWSLib
{
public class EditableGrid : DataGrid
{
public EditableGrid()
{
AllowFullEditing = true;
AddNewRow = false;
AllowPaging = true;
RejectChanges = false; // internal use
MustInsertRow = false; // internal use

// Handlers
Init += new EventHandler(OnInit);
PageIndexChanged += new
DataGridPageChangedEventHandler(OnPageIndexChanged);
ItemCreated += new DataGridItemEventHandler(OnItemCreated);
CancelCommand += new DataGridCommandEventHandler(OnCancelCommand);
EditCommand += new DataGridCommandEventHandler(OnEditCommand);
UpdateCommand += new DataGridCommandEventHandler(OnUpdateCommand);
DeleteCommand += new DataGridCommandEventHandler(OnDeleteCommand);
}
:
}
}

EditableGrid 类有一个尚未提到的公共属性 — AllowFullEditing。该属性成员支持对网格的完全编辑功能。如果您将该属性设置为 false,则该控件将不提供就地编辑或插入功能。究竟执行的是怎样的处理?该控件自动将 AllowPaging 设置为 true,并为 PageIndexChanged 提供一个处理程序。这意味着 EditableGrid 还是比 DataGrid 控件好一些,因为它为您提供自动的空闲分页。

当 AllowFullEditing 设置为 true(默认值)时,EditableGrid 控件自动将两个新列追加到网格中。第一列是 EditCommandColumn,它提供就地编辑功能。第二列是 ButtonColumn,它的命令是 DELETE。这两列都是通过为响应 Init 事件而运行的处理程序来添加的。

public void OnInit(Object sender, EventArgs e)
{
if (AllowFullEditing)
AddWorkerColumns();
}

private void AddWorkerColumns()
{
// Edit column
EditCommandColumn editColumn = new EditCommandColumn();
editColumn.EditText = EditColumnText;
editColumn.UpdateText = EditColumnUpdateText;
editColumn.CancelText = EditColumnCancelText;
Columns.Add(editColumn);

// Delete column
ButtonColumn deleteColumn = new ButtonColumn();
deleteColumn.CommandName = "delete";