4

我有一个返回 DataTable 的函数,我可以将它数据绑定到 DropDownlist 或 Repeater 就好了。但是,如果我对 DataTable 的 DataRows 的 IEnumerable 进行数据绑定,则会收到 HttpException:“DataBinding:'System.Data.DataRow' 不包含名为 'some_column' 的属性”。

repeater.DataSource = ThisReturnsDataTable();  // Works fine
repeater.DataSource = ThisReturnsDataTable.AsEnumerable();  // HttpException

为什么是这样?

我不是在寻找解决问题的方法,例如:

repeater.DataSource = ThisReturnsDataTable().AsEnumerable().Select(
    x => new {some_column = x["some_column"]});

我只是想知道为什么使用 DataRows 的 IEnumerable 的数据绑定会失败。

4

2 回答 2

11

我在这里找到了一个很好的解释,尽管他对问题的第一个解决方案AsDataView()似乎不起作用/不存在(至少在 3.5 中)。CopyToDataTable()不过,工作得很好。

.Net DataTables 在编写数据驱动的应用程序时非常有用。但是,它们有一个限制:没有明显的方法可以将网格(或其他控件)数据绑定到表中的任意数据行列表。您可以通过将 DataSource 设置为 DataTable 本身来直接绑定到整个表,也可以通过使用过滤器创建 DataView 来绑定到表的子集。

通常,您不能绑定到 IEnumerable(例如,LINQ 查询);数据绑定基础结构只能处理 IList(非泛型)或 IListSource。这适用于任何类型的数据源。因此,要绑定到任何 LINQ 查询,您需要调用 .ToList()。(或 .ToArray())

但是,当绑定到 DataTable 时,您甚至不能使用 List。如果您尝试,您将获得四列(RowError、RowState、Table 和 HasErrors)并且没有有用的信息。发生这种情况是因为 List 没有告诉数据绑定基础结构有关 DataRows 的特殊属性。要理解这个问题,需要一些背景知识

数据绑定由 ListBindingHelper 和 TypeDescriptor 类控制。绑定到列表时,会调用 ListBindingHelper.GetListItemProperties 方法来获取列表中的列。如果列表实现了 ITypedList 接口,则调用其 GetItemProperties 方法。否则,它将使用 TypeDescriptor 来获取列表中第一项的属性。(这使用反射)

DataView 类(DataTable 也通过它绑定,使用 IListSource)实现 ITypedList 并返回显示表中列的 DataColumnPropertyDescriptors。这就是您可以绑定到 DataView 或 DataTable 并查看列的原因。但是,当您绑定到列表时,没有可以将列作为属性返回的 ITypedList。因此,它依靠反射并显示 DataRow 类的物理属性。

要解决此问题,您需要将列表包装在 DataView 中,以便您可以利用其 ITypedList 实现。您可以使用 AsDataView() 方法来做到这一点。此方法仅适用于 DataTable 和 EnumerableRowCollection 类;它不能在任意 LINQ 查询上调用。您只能通过从 DataTable 调用特殊版本的 Cast、OrderBy、Where 和 Select 方法来获取 EnumerableRowCollection。

因此,您可以通过对查询调用 AsDataView() 来将数据绑定到简单的 LINQ 查询。要绑定到列表或更复杂的查询,您可以使用丑陋的 hack:

    List<DataRow> list = ...; 
    grid.DataSource = datatable.AsEnumerable()
                   .Where(list.Contains)
                   .AsDataView();

类型化数据集不需要 AsEnumerable() 调用。

您还可以调用 CopyToDataTable(),它将在任意 IEnumerable 上工作 [原文如此]。但是,它会生成行的深层副本,因此如果您希望用户更新数据,或者如果您希望用户查看(在代码中)对原始数据行所做的更改,则它没有帮助。

来自:http: //blog.slaks.net/2011/01/binding-to-lists-of-datarows.html

于 2012-04-24T09:42:52.240 回答
0

我可能是错的,但我相信.Where你应该能够做这样的事情,而不是做这个条款:

DirectCast([datatable].AsEnumerable, EnumerableRowCollection(Of DataRow)).AsDataView()
于 2012-09-14T17:40:54.993 回答