65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET 绑定:DataGrid 到垂直表

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.42/5 (8投票s)

2005年1月3日

4分钟阅读

viewsIcon

146005

downloadIcon

1648

一种在 ASP.NET 中将垂直表与 DataGrid 绑定的简单方法

Sample Image - AspNetBindDatagridVT.gif

背景

传统上,数据库方法将表表示为记录列表。在编程语言中,这相当于结构的**一维数组(列表)**。

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>

代码隐藏类的骨架如下:

注意:只有标记为省略号 (...) 的部分会在数据源之间有所不同,即 DataTypeCreateDataSourceGenerateColumns

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 而非全大写)。DataGridAutoGenerateColumns 属性默认是打开的,但它会忽略 DataColumnCaption。因此,我们需要特别努力手动设置它。

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 中,有一个内置机制可以绑定到自定义记录的 ArrayArrayList。这是根据 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 或自定义记录的 ArrayArrayList 那样的自动支持。

我们的策略将基于 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.FormsWeb.UI 之间存在对称性的承诺,但当跳出 DataSet 的标准情况时,DataGrid 绑定工作方式却大不相同。这是因为 Windows.Forms 绑定的双向交互性与 Web.UI 不同。类似地使用 Windows.Forms 绑定将是另一个独立研究的主题。

参考文献

历史

  • 2005 年 1 月 2 日:Oleg Kobchenko - 初稿

许可证

本文没有明确的许可证,但可能包含文章文本或下载文件本身的使用条款。如有疑问,请通过下面的讨论区与作者联系。作者可能使用的许可证列表可在此处找到。

© . All rights reserved.