I've been cruising around the interwebs trying to figure this out but I cant.
I have a BindingSource
to which I .add
a bunch of FileInfo
s from .GetFiles
.
When I step through, the BindingSource
's SupportsSorting
property is False
. I don't understand why.
I tried setting the BindingSource.DataSource
to a BindingList
in stead of adding each FileInfo
one by one, but then the underlying list is still of type IList
.
Here's my code:
If Directory.Exists(configPath) Then
For Each foundFile As FileInfo In New DirectoryInfo(configPath).GetFiles("*.csv", SearchOption.TopDirectoryOnly)
If foundFile.Length >= My.Settings.scanFileSizeThreshold Then
scansBindingSource.Add(foundFile)
End If
Next
Else
All I want to do is something like this:
scansBindingList.Sort = "LastWriteTime Desc"
And have the data in a DataGridView sorted by last write time. Is this possible? Thanks!
The BindingList
does not support sorting. As well on MSDN has this for BindingSource
:
If the data source is not an IBindingList, the SupportsSorting property always returns false.
You can have NET deliver the files to you in the order of LastWriteTime
so that you dont have to sort them (and also get rid of the loop):
Dim theFiles = New DirectoryInfo(fpath).EnumerateFiles(fmask, SearchOption.TopDirectoryOnly).
Where(Function(f) f.Length > szMin).
OrderByDescending(Function(s) s.LastWriteTime)
dgv2.DataSource = New BindingSource(theFiles, Nothing)
NET will put the files in order and exclude the files which do not match rather than deliver them to you just to be tested and excluded. The result is an IEnumerable
which the binding source can use directly.
If you want to be able to add to a list of these and sort them, use a List(Of FileInfo)
for storage and sorting and then a BindingSource
for adding/deleting.
Private filesBS As BindingSource
Private FilesList As List(Of FileInfo)
...
FilesList = New DirectoryInfo(...).EnumerateFiles("*.csv", SearchOption.AllDirectories).
Where(Function(f) f.Length > MinSize).
OrderByDescending(Function(q) q.LastWriteTime).
ToList()
filesBS = New BindingSource(FilesList, Nothing)
dgv2.DataSource = filesBS
The files query is the same as before, I just added ToList()
; then use it for the BindingSource
. If you add and remove items via the BindingSource
they will show in the collection and DGV.
filesBS.RemoveAt(0)
filesBS.Add(newItem)
The dreary part is sorting because it has to be done 'manually' (which is to say the DGV wont /cant do it) and because there are so many properties to FileInfo
. One way to sort is to use extension methods as was done in the query:
' sort by file size
If fileSortOrder = SortOrder.Ascending Then
FilesList = FilesList.OrderBy(Function(f) f.Length).ToList()
Else
FilesList = FilesList.OrderByDescending(Function(f) f.Length).ToList()
End If
filesBS = New BindingSource(FilesList, Nothing)
' ToDo: toggle fileSortOrder like below
dgv2.DataSource = filesBS
Note that since the FilesList
collection is recreated, you need to rebuild the BindingSource
as well. You can also use the Sort
method:
FilesList.Sort(AddressOf FileInfoSizeCompare)
dgv2.Refresh()
...
Private fileSortOrder As SortOrder = SortOrder.Ascending
Private Function FileInfoSizeCompare(x As FileInfo, y As FileInfo) As Int32
Dim sortReverser As Int32 = If(fileSortOrder = SortOrder.Ascending, 1, -1)
Dim ret As Int32 = 0
If x.Length < y.Length Then ret = -1
If x.Length > y.Length Then ret = 1
Return (ret * sortReverser)
End Function
In this case, since the list is not recreated, you just need to refresh the control to redraw the contents. You will need a different method for each column/property you wish to sort by. With either approach, if you invoke the methods from the ColumnHeaderMouseClick
event, it will work like it does when the DGV can sort the DataSource
.
If I were to use the second version, I might put the Sort methods in a class so that a) I could reuse them and b) to get all that code out of the forms.