2012-04-24 64 views
4

我有一个函数返回一个DataTable,我可以绑定到DropDownlist或Repeater就好了。但是,如果我databind IEnumerable的DataTable的DataRows,我得到一个HttpException:“DataBinding:'System.Data.DataRow'不包含属性的名称'some_column'”。无法数据绑定IEnumerable的DataRows? HttpException?

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

这是为什么?

我不是寻找一个解决问题的办法,例如像:

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

我只是想知道为什么有数据行的IEnumerable的数据绑定失败。

回答

11

我发现了一个很好的解释here,尽管他对问题的第一个解决方案AsDataView()似乎没有工作/存在(至少在3.5中)。尽管如此,CopyToDataTable()仍然可以运作。

。当编写数据驱动的 应用程序时,Net DataTable可能非常有用。但是,它们有一个局限性:没有明显的方式将表格(或其他控件)数据绑定到任意数据行的列表 。您可以通过将数据源设置为DataTable本身直接绑定到整个表,并且可以通过创建带有过滤器的DataView绑定到表的子集。

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

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

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

DataView类(其数据表也通过结合使用 IListSource)实现ITypedList并返回 DataColumnPropertyDescriptors暴露在表中的列。 这就是为什么你可以绑定到DataView或DataTable并查看列。 但是,当您绑定到列表时,不会有ITypedList可以将列作为属性返回。因此它会回退 反射并显示DataRow类的物理属性。

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

因此,您可以通过在查询中调用 AsDataView()来将数据绑定到简单的LINQ查询。绑定到一个列表,或更复杂的 查询,你可以使用一个丑陋的黑客:是不是需要类型化数据集

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

的AsEnumerable()调用。

您也可以调用CopyToDataTable(),它将在任意的IEnumerable上调用[sic]任意的 。但是,它会对行进行深层复制,因此如果您希望用户更新数据,或者您希望用户查看(在代码中)对原始数据行进行的更改,则无关紧要。

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

0

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

DirectCast([datatable].AsEnumerable, EnumerableRowCollection(Of DataRow)).AsDataView()