ASP.NET 绑定:DataGrid 到垂直表






4.42/5 (8投票s)
2005年1月3日
4分钟阅读

146005

1648
一种在 ASP.NET 中将垂直表与 DataGrid 绑定的简单方法
背景
传统上,数据库方法将表表示为记录列表。在编程语言中,这相当于结构的**一维数组(列表)**。
public struct Account { // record
public string Name { get; set; }
public double Balance { get; set; }
}
public Account[] Accounts; // table
然而,在某些应用程序中,出于性能和其他原因,将数据结构**转置**为一个列表集合是可行的,其中集合的项是给定列的值列表。在编程语言中,可以表示为:
public class Accounts { // vertical table
public string[] Name;
public double[] Balance;
}
由列集合组成的数据结构称为**垂直表**。
绑定 DataTable
ASP.NET 中最常见的数据源之一是 DataSet
成员,也称为 DataTable
。我们将使用这种类型的绑定作为与其他数据类型进行比较的起点。
代码中的所有示例都包含相同类型的 .aspx 文件以及不同的代码隐藏文件。.aspx 文件的主体包含一个 DataGrid
。
<form id="Form1" method="post" runat="server">
<asp:datagrid id="DataGrid1" runat="server">
</asp:datagrid>
</form>
代码隐藏类的骨架如下:
注意:只有标记为省略号 (...) 的部分会在数据源之间有所不同,即 DataType
、CreateDataSource
和 GenerateColumns
。
public class DataSetBind : System.Web.UI.Page
{
protected System.Web.UI.WebControls.DataGrid DataGrid1;
protected DataType dt = ... // Particular data source type
private void CreateDataSource() {
// ...
}
private void GenerateColumns(DataGrid grid) {
// ...
}
private void Page_Load(object sender, System.EventArgs e)
{
CreateDataSource();
DataGrid1.DataSource = dt;
GenerateColumns(DataGrid1);
DataBind();
}
#region Web Form Designer generated code
// ...
}
对于 DataTable
源类型,我们通过指定架构并填充行来创建数据源。
protected DataTable dt = new DataTable("ACCOUNT");
private void CreateDataSource() {
DataColumn col = null;
col = dt.Columns.Add("NAME", typeof(string));
col.Caption = "Name";
col = dt.Columns.Add("BALANCE", typeof(double));
col.Caption = "Balance";
// Fill data table
dt.Rows.Add(new object[]{"One", 123.45});
dt.Rows.Add(new object[]{"Two", 0});
dt.Rows.Add(new object[]{"Three", -123.45});
}
原则上,这足以绑定到 DataGrid
,除非您关心设置与列数据成员名称不同的标题(此处为 Title case 而非全大写)。DataGrid
的 AutoGenerateColumns
属性默认是打开的,但它会忽略 DataColumn
的 Caption
。因此,我们需要特别努力手动设置它。
private void GenerateColumns(DataGrid grid) {
grid.AutoGenerateColumns = false;
foreach (DataColumn col in dt.Columns) {
BoundColumn dc = new BoundColumn();
dc.DataField = col.ColumnName;
dc.HeaderText = col.Caption;
grid.Columns.Add(dc);
}
}
绑定自定义记录数组
在 ASP.NET 中,有一个内置机制可以绑定到自定义记录的 Array
或 ArrayList
。这是根据 BaseDataList.DataSource 属性定义中的说明得出的。
我们将使用以下形式的自定义记录:
public struct TestStruct {
private string _NAME;
private double _BALANCE;
[View("Name")]
public string NAME { get { return _NAME; } }
[View("Balance")]
public double BALANCE { get { return _BALANCE; } }
public TestStruct(string NAME, double BALANCE) {
_NAME = NAME;
_BALANCE = BALANCE;
}
}
数据源将是我们 struct
的一个简单数组:
protected TestStruct[] dt = null;
private void CreateDataSource() {
dt = new TestStruct[]{
new TestStruct("One", 123.45),
new TestStruct("Two", 0),
new TestStruct("Three", -123.45),
};
}
使用属性以声明方式指定标题
我们将在此处发挥创意,将标题封装在 struct
的声明中,并在列生成例程中通用地发现它们。首先,我们定义一个自定义属性类,如下所示:
public class ViewAttribute : Attribute {
protected string _caption = "";
protected string _format = "";
public ViewAttribute(string caption) : this(caption, "") { }
public ViewAttribute(string caption, string format) {
_caption = caption;
_format = format;
}
public string Caption { get { return _caption; } }
public string Format { get { return _format; } }
}
该属性在上面的 struct
声明中用作 [View("Name")]
。
然后,列生成将如下所示:
注意:这样的发现将允许选择性地显示用 View
属性标记的 struct
属性,隐藏所有其他属性,从而为其他用途提供更多属性。
private static void GenerateColumns(DataGrid grid) {
grid.AutoGenerateColumns = false;
foreach (PropertyInfo pi in typeof(TestStruct).GetProperties()) {
ViewAttribute[] attrs =
pi.GetCustomAttributes(typeof(ViewAttribute), false)
as ViewAttribute[];
if (attrs.Length <= 0)
continue;
BoundColumn dc = new BoundColumn();
dc.DataField = pi.Name;
dc.HeaderText = attrs[0].Caption;
dc.DataFormatString = attrs[0].Format;
grid.Columns.Add(dc);
}
}
绑定垂直表
对于垂直表,ASP.NET DataGrid
没有像 DataTable
或自定义记录的 Array
和 ArrayList
那样的自动支持。
我们的策略将基于 DataSource
属性的定义,该属性指出数据源必须是实现 System.Collections.IEnumerable
接口的对象。枚举器将遍历记录列表,类似于自定义记录示例,但是记录本身不会是数据的实际容器,而是一个访问器,通过其属性公开实际位于垂直表列中的数据。这种设计模型称为 享元模式(Flyweight Pattern)。
成员是值列数组的 VerticalTable
类将作为 IEnumerable
。
public class TestTable : IEnumerable {
internal string[] _NAME = null;
internal double[] _BALANCE = null;
public TestTable(string[] NAME, double[] BALANCE) {
_NAME = NAME;
_BALANCE = BALANCE;
}
public int Count { get {
return _NAME == null ? 0 : _NAME.Length; }}
#region IEnumerable Members
public IEnumerator GetEnumerator() {
return new TestRecord(this);
}
#endregion
}
IEnumerable.GetEnumerator()
将返回我们自定义记录访问器的一个新实例,该实例还将充当自身上的 IEnumerator
。它将简单地迭代对所引用垂直表中数组位置的索引。
public class TestRecord : IEnumerator {
TestTable _testTable = null;
int _pos = -1;
[View("Name", "")]
public string NAME { get { return _testTable._NAME[_pos]; } }
[View("Balance", "<tt>{0:F2}</tt>")]
public double BALANCE { get { return _testTable._BALANCE[_pos]; } }
public TestRecord(TestTable testTable) {
_testTable = testTable;
}
#region IEnumerator Members
public bool MoveNext() {
if (_pos >= _testTable.Count - 1)
return false;
_pos++;
return true;
}
public object Current { get { return this; } }
public void Reset() { _pos = -1; }
#endregion
}
请注意,我们如何使用相同的 View
属性进行列生成。只有这样标记的属性才会进入 DataGrid
的列。因此,我们使用(几乎)相同的 GenerateColumns
例程,发现访问器记录的自定义属性。
另外,请注意此处用于设置 DataFormatString
的技巧,通过 View
属性的格式部分,部分使用了格式良好的 HTML(<tt>
),DataGrid
渲染器会适当地使用它来获得格式化效果。
创建数据源如下所示:
protected TestTable dt = null;
private void CreateDataSource() {
dt = new TestTable(
new string[]{"One", "Two", "Three"},
new double[]{123.45, 0, -123.45});
}
关注点
此处使用的设计决策用于说明 DataGrid
绑定的目的。在实际情况中,可以进行进一步的增强,例如将自定义记录和垂直表通用化,以动态处理列和记录的数量。
尽管 Windows.Forms
和 Web.UI
之间存在对称性的承诺,但当跳出 DataSet
的标准情况时,DataGrid
绑定工作方式却大不相同。这是因为 Windows.Forms
绑定的双向交互性与 Web.UI
不同。类似地使用 Windows.Forms
绑定将是另一个独立研究的主题。
参考文献
- Mihail Stefanov,将二维数组绑定到 DataGrid
- Tarun Jain, .NET Windows Forms 中的数据绑定概念
- Alastair Stell,DataGrid Zen 初学者
- Neeraj Jain,在 DataGrid 中显示垂直行
- Jan Tielens,通过 Web 服务公开自定义类并将其绑定到 DataGrid
- Marcie Robillard,(Datagrid Girl)分离 DataGrid 项
- omri,DataGrid101 - 使用 Windows.Forms DataGrid
- Dino Esposito,深入了解 .NET Windows Forms 数据绑定
历史
- 2005 年 1 月 2 日:Oleg Kobchenko - 初稿
许可证
本文没有明确的许可证,但可能包含文章文本或下载文件本身的使用条款。如有疑问,请通过下面的讨论区与作者联系。作者可能使用的许可证列表可在此处找到。