4

DropDownlistまたはRepeaterにデータバインドできるDataTableを返す関数があります。ただし、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"]});

IEnumerableofDataRowsを使用したデータバインディングが失敗する理由を知りたいだけです。

4

2 に答える 2

11

私はここでかなり良い説明を見つけましたが、問題に対する彼の最初の解決策は、AsDataView()(少なくとも3.5では)機能/存在しないようです。CopyToDataTable()しかし、泳いで動作します。

.Net DataTablesは、データ駆動型アプリケーションを作成するときに非常に役立ちます。ただし、1つの制限があります。グリッド(または他のコントロール)をテーブルのデータ行の任意のリストにデータバインドする明確な方法はありません。DataSourceをDataTable自体に設定することでテーブル全体に直接バインドでき、フィルターを使用してDataViewを作成することでテーブルのサブセットにバインドできます。

一般に、IEnumerable(LINQクエリなど)にバインドすることはできません。データバインディングインフラストラクチャは、IList(非ジェネリック)またはIListSourceのみを処理できます。これは、あらゆる種類のデータソースに当てはまります。したがって、LINQクエリにバインドするには、.ToList()を呼び出す必要があります。(または.ToArray())

ただし、DataTableにバインドする場合、リストを使用することもできません。試してみると、4つの列(RowError、RowState、Table、およびHasErrors)が表示され、有用な情報は得られません。これは、リストがDataRowsの特別なプロパティについてデータバインディングインフラストラクチャに通知しないために発生します。問題を理解するには、いくつかの背景が必要です

データバインディングは、ListBindingHelperクラスとTypeDescriptorクラスによって制御されます。リストにバインドすると、ListBindingHelper.GetListItemPropertiesメソッドが呼び出され、リスト内の列が取得されます。リストがITypedListインターフェースを実装している場合、そのGetItemPropertiesメソッドが呼び出されます。それ以外の場合は、TypeDescriptorを使用して、リストの最初のアイテムのプロパティを取得します。(これは反射を使用します)

DataViewクラス(DataTableもIListSourceを使用してバインドします)はITypedListを実装し、テーブルの列を公開するDataColumnPropertyDescriptorsを返します。これが、DataViewまたはDataTableにバインドして列を表示できる理由です。ただし、リストにバインドする場合、列をプロパティとして返すことができるITypedListはありません。したがって、リフレクションにフォールバックし、DataRowクラスの物理プロパティを表示します。

この問題を解決するには、リストをDataViewでラップして、ITypedList実装を利用できるようにする必要があります。AsDataView()メソッドを使用してこれを行うことができます。このメソッドは、DataTableクラスとEnumerableRowCollectionクラスでのみ使用できます。任意のLINQクエリで呼び出すことはできません。EnumerableRowCollectionを取得するには、DataTableからCast、OrderBy、Where、およびSelectメソッドの特別なバージョンを呼び出す必要があります。

したがって、クエリで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

于 2012-04-24T09:42:52.240 に答える
0

私は間違っている可能性がありますが、.Where条項を実行する代わりに、次のようなことができるはずです。

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