This might seem like a repeated question, but I am looking for a specific function. I have looked through similar questions on StackOverflow and Google and tried using many different code examples, but up to now, without success?
What I Am Doing:
Form1_Load
, I call a function to display File Info in a DataGridView for all the files in "MyFolder".My Code:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
'Call Function To Display File Info From MyFolder:
DataGridView1.DataSource = Fileinfo_To_DataTable("C:\Users\" + username + "\Documents\MyApp\MyFolder")
End Sub
'Next Button:
Private Sub btnNext_Click(sender As Object, e As EventArgs) Handles btnNext.Click
If DataGridView1.SelectedRows(0).Index < DataGridView1.RowCount - 1 Then
MyDesiredIndex = DataGridView1.SelectedRows(0).Index + 1
Else
MyDesiredIndex = 0
End If
DataGridView1.ClearSelection()
DataGridView1.CurrentCell = DataGridView1.Rows(MyDesiredIndex).Cells(0)
DataGridView1.Rows(MyDesiredIndex).Selected = True
End Sub
'Previous Button:
Private Sub btnPrev_Click(sender As Object, e As EventArgs) Handles btnPrev.Click
If DataGridView1.CurrentCell.RowIndex >= 0 And DataGridView1.CurrentCell.RowIndex <= DataGridView1.Rows.Count - 1 Then
For Each row As DataGridViewRow In DataGridView1.Rows
If Not row.IsNewRow Or vbNull Then
MyDesiredIndex = DataGridView1.SelectedRows(0).Index - 1
End If
Next
End If
DataGridView1.ClearSelection()
DataGridView1.CurrentCell = DataGridView1.Rows(MyDesiredIndex).Cells(0)
DataGridView1.Rows(MyDesiredIndex).Selected = True
End Sub
The Problem:
The Next button cycles in a "continuous loop" through all DGV rows without exceptions. By "continuous loop" I mean that my program cycles through all rows without stopping, either at the first row (0) or at the last row (i.e. cycling occurs as long as I continue to press the Next button).
The Previous button only works if I first use the Next button to change the selected row (i.e. First > Last). Then, hitting the Previous button changes the selected row returning to the first row (i.e. Last > First). But, when the program reaches the first row it throws an exception as follows:
"System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index'"
What I Have Tried:
Besides my attempt above (and many others), I found the following code on StackOverflow which addresses the same issue, but which also stops at the first row without cycling through all rows:
Moving to previous row in datagridview
Moving to previous row in datagridview
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim i As Integer = DataGridView1.CurrentRow.Index - 1
If i < 0 Then i = 0
DataGridView1.CurrentCell = Me.DataGridView1.Rows(i).Cells(0)
DataGridView1.Rows(i).Selected = True
End Sub
Desired behaviour:
I would appreciate any help to cause the Previous button to behave in the same way as the Next button, i.e. cycle through all the rows continuously without throwing an exception.
I have made many attempts to find logic to "contain" selection of previous rows within the range, but without success. But, I really like the way the Next button cycles continuously through the rows without stopping and would like to copy this behaviour to the Previous button to be able to continuously cycle both ways (i.e. Next/Previous) without stopping? I have also tried several different For Each
loops, but couldn't get the code working in the desired way?
Does anyone have any ideas how I can achieve this?
Using a BindingSource as mediator between your data source of FileInfo objects and the DataGridView, you can directly make use of the BindingSource, MovePrevious(), MoveNext(), MoveFirst() and MoveLast() methods.
Note that all these are void
methods (Sub
), none returns a state, but you can determine the current position in the data source using the Position property.
OnLoad()
method override (or Form.Load
event handler, as you prefer), create the collection of FileInfo
objects, set this collection as the DataSource of your BindingSource and the BindingSource as the DataSource of your DataGridView:Private fileListSource As BindingSource = Nothing
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
Dim docsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
Dim filesPath = Path.Combine(docsPath, "MyApp\MyFolder")
fileListSource = New BindingSource(New DirectoryInfo(filesPath).GetFiles("*.txt"), Nothing)
DataGridView1.DataSource = fileListSource
End Sub
Now, you can use four Buttons to move the Current
object (see also the CurrencyManager class), using the aforementioned methods of your BindingSource, checking the Current
objects's position to determine whether you have to move Current
to the first or last object when the Next or Previous Buttons are clicked:
Private Sub btnMoveFirst_Click(sender As Object, e As EventArgs) Handles btnMoveFirst.Click
fileListSource.MoveFirst()
End Sub
Private Sub btnMoveLast_Click(sender As Object, e As EventArgs) Handles btnMoveLast.Click
fileListSource.MoveLast()
End Sub
Private Sub btnMovePrevious_Click(sender As Object, e As EventArgs) Handles btnMovePrevious.Click
If fileListSource.Position > 0 Then
fileListSource.MovePrevious()
Else
fileListSource.MoveLast()
End If
End Sub
Private Sub btnMoveNext_Click(sender As Object, e As EventArgs) Handles btnMoveNext.Click
If fileListSource.Position < fileListSource.Count - 1 Then
fileListSource.MoveNext()
Else
fileListSource.MoveFirst()
End If
End Sub
This is how it works:
Unfiltered list of files here
Using DataBinding, you can bind other Controls to the BindingSource and interact with its source of data, a collection of FileInfo objects in this case.
This means that when you change a property value of bound Controls, the Properties of current object in the collection also change.
Since you have FileInfo objects, this reflects automatically on the underlying File object, changing its attributes.
Here, ReadOnly
, CreationTime
and LastWriteTime
are changed using a CheckBox and two DateTimePickers.
dtpLastWrite.DataBindings.Add("Value", fileListSource, "LastWriteTime", True, DataSourceUpdateMode.OnPropertyChanged)
dtpCreationTime.DataBindings.Add("Value", fileListSource, "CreationTime", False, DataSourceUpdateMode.OnPropertyChanged)
chkReadOnly.DataBindings.Add("Checked", fileListSource, "IsReadOnly", False, DataSourceUpdateMode.OnPropertyChanged)