I'm working on a system that currently has a fairly complicated function that returns a DataTable, which it then binds to a GUI control on a ASP.NET WebForm.
My problem is that I need to filter the data returned - some of the data that is being returned should not be displayed to the user.
I'm aware of DataTable.select(), but that's not really what I need. First, it returns an array of D开发者_如何学GoataRows, and I need a DataTable, so I can databind it to the GUI control. But more importantly, the filtering I need to do isn't something that can be easily put into a simple expression. I have an array of the elements which I do not want displayed, and I need to compare each element from the DataTable against that array.
What I could do, of course, is to create a new DataTable, reading everything out of the original, adding to the new what is appropriate, then databinding the new to the GUI control. But that just seems wrong, somehow. In this case, the number of elements in the original DataTable aren't likely to be enough that copying them all in memory is going to cause too much trouble, but I'm wondering if there is another way.
Does the .NET DataTable have functionality that would allow me to filter via a callback function?
Use the DataView.ToTable
method:
DataTable sourceTable = ...
string filter = ...
string sort = ...
DataView view = new DataView(sourceTable, filter, sort, DataViewRowState.CurrentRows);
DataTable newTable = view.ToTable();
If you can't put your filtering logic in a filter expression, you can resort to Linq to DataSet:
var query = from row in sourceTable.AsEnumerable()
where row.Field<int>("foo") > 42
&& row.Field<string>("bar") == "hello"
&& ...
select r;
var newTable = query.AsDataView().ToTable();
Or, if you already have a method that implements the filtering:
bool FilterRow(DataRow row)
{
...
}
...
var newTable = sourceTable.AsEnumerable().Where(FilterRow).AsDataView().ToTable();
What about binding the GUI Control To a List of DataRows which satisfies your condition? something like this:
var lst = new List<DataRow>();
foreach(DataRow dr in dt.Rows) {
if (SatisfiesCondition(dr)) lst.Add(dr);
}
// in Linq dialect
var lst = dt.AsEnumerable().Where(SatisfiesCondition).ToList();
// here: bind control to list
Doing it this way, the datarows won't be copied, but the list will keep the references to the rows you need.
I don't know what you mean with a callback function.
Probably others will recommend LINQ for this. But because i'm still using 3.5 Framework, i'm not familiar with it.
How many rows does your Datatable have? It might be sufficient to use Datatable.Select:
Private Function SelectIntoDataTable(ByVal selectFilter As String, ByVal sourceDataTable As DataTable) As DataTable
Dim newDataTable As DataTable = sourceDataTable.Clone
Dim dataRows As DataRow() = sourceDataTable.Select(selectFilter)
Dim typeDataRow As DataRow
For Each typeDataRow In dataRows
newDataTable.ImportRow(typeDataRow)
Next
Return newDataTable
End Function
You can also use a Dataview as source of your second control with using its RowFilter property:
DataView dv = new DataView( sourceDataTable );
dv.RowFilter = selectFilter
GridView1.DataSource = dv
You can also use the IN
and NOT IN
Syntax to filter by a list/array of items for Select and RowFilter, for example:
dv.RowFilter = "SomeID NOT IN(1,2,3)"
精彩评论