Moving through datagridview rows on keypress - vb.net

I'm trying to go through datagridview rows where the cell value starts with the same keychar the user pressed. Code bellow works, but It wont move selection to next row starting with same letter when I press same letter second, third time...
Private Sub dataGridView1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles dgw.KeyPress
If [Char].IsLetter(e.KeyChar) Then
For i As Integer = 0 To (dgw.Rows.Count) - 1
If dgw.Rows(i).Cells(1).Value.ToString().StartsWith(e.KeyChar.ToString(), True, CultureInfo.InvariantCulture) Then
If lastKey = e.KeyChar And lastIndex < i Then
Continue For
End If
lastKey = e.KeyChar
lastIndex = i
dgw.Rows(i).Cells(1).Selected = True
Return
End If
Next
End If
End Sub

Seems like a flaw in the logic. You press key, save index and break. Then you press the same key. And if lastIndex is lesser than i you continue. Which means it will only select the first row it finds with a lesser value than the last one. Change to lastindex > i and you should be fine.
You can with the code you have written never get anything else than the first line matching the key. After that it doesn't matter how many times you press.

I know that is too old this post... anyway I've found a workaround for this and maybe it will be useful for someone.
public lastkey as string
Private Sub dataGridView1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles dgw.KeyPress
Dim input = StrConv(e.keychar.toString()
lastkey += input
Dim found as Boolean
if StrConv(dgw.currentCell.Value.toString.Substring(0,1), VbStrConv.UpperCase) = input then
dim curIndex = dgw.currentRow.Index
if curIndex < dgw.rows.count - 1 then
dgw.ClearSelection()
curIndex += 1
dgw.currentCell = dgw.rows(curIndex).Cells(0)
dgw.rows(curIndex).selected = true
end if
else
dgv_jumpRecord(lastkey,found)
if not found then
lastkey = input
dgv_jumpRecord(lastkey,found)
end if
End if
End Sub
Public Sub dgv_jumpRecord(byVal lastkey as String, ByRef found as boolean)
For i As Integer = 0 To (dgw.Rows.Count) - 1
dim rowText = dgw.Rows(i).Cells(1).Value.ToString
If StrConv(rowText.ToString(),VbStrConv.UpperCase).StartsWith(lastkey) Then
dgw.ClearSelection()
dgw.CurrentCell = dgw.rows(i).Cells(0)
dgw.rows(i).selected = true
found = true
Exit Sub
End If
Next
found = false
End Sub

Related

Change datagriview cell value on CellValidating

I would like to change the value of cell value which user inputs there and do the trim before to avoid left and right spaces over value before it will be validated. Currently this is my code without this feature:
Private Sub Grid_CellValidating(sender As Object, e As DataGridViewCellValidatingEventArgs) Handles Grid.CellValidating
Dim newValue = e.FormattedValue.ToString
If Not Grid.Rows(e.RowIndex).IsNewRow Then 'And Not e.RowIndex = Grid.NewRowIndex - 1 Then
Select Case e.ColumnIndex
Case 1 'Name
If String.IsNullOrEmpty(newValue) Then
e.Cancel = True
Exit Select
End If
Case Else
End Select
End If
End Sub
What I tried to do was this way, but it completely doesn't work:
Private Sub Grid_CellValidating(sender As Object, e As DataGridViewCellValidatingEventArgs) Handles Grid.CellValidating
Dim newValue = e.FormattedValue.ToString.Trim '<---trim added
'change value of cell without trims
Dim aaa As DataGridViewCell = CType(sender, DataGridView).Rows(e.RowIndex).Cells(e.ColumnIndex)
aaa.Value = newValue
If Not Grid.Rows(e.RowIndex).IsNewRow Then 'And Not e.RowIndex = Grid.NewRowIndex - 1 Then
Select Case e.ColumnIndex
Case 1 'Name
If String.IsNullOrEmpty(newValue) Then
e.Cancel = True
Exit Select
End If
Case Else
End Select
End If
End Sub
That's the wrong event. CellValidating is for determining whether the contents of the cell is valid or not. CellValidated or CellLeave would be more suited to your situation.
In the CellValidating event this works for me.
//remove the event
grdDetails.CellValidating -= grdDetails_CellValidating;
//update current cell
grdDetails.CurrentCell.Value = "My New Value";
//force grid to commit update
grdDetails.EndEdit();
//rehook the event
grdDetails.CellValidating += grdDetails_CellValidating;

Keep focus on row after datagridview update

I'm creating an VB windows application. The point of the application is a simple DataGridView where I'm fetching a View from a SQL Server database.
The DataGridView is refreshed every second so I could see new data income in my GridView.
The problem is keeping focus on row after the refresh. I need the solution, where after I click a row, or a cell it keeps me on it even after the refresh.
Here is my code:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Refresh every 1 sec
Dim timer As New Timer()
timer.Interval = 1000
AddHandler timer.Tick, AddressOf timer_Tick
timer.Start()
'TODO: This line of code loads data into the 'XYZDataSet.view1' table. You can move, or remove it, as needed.
Me.View1TableAdapter.Fill(Me.XYZDataSet.view1)
End Sub
Private Sub DataGridView1_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
End Sub
Private Sub DataGridView1_CellFormatting(ByVal sender As Object, ByVal e As DataGridViewCellFormattingEventArgs) Handles DataGridView1.CellFormatting
For i As Integer = 0 To Me.DataGridView1.Rows.Count - 1
If Me.DataGridView1.Rows(i).Cells("DayTillDelivery").Value <= 30 Then
Me.DataGridView1.Rows(i).Cells("DayTillDelivery").Style.ForeColor = Color.Red
End If
Next
End Sub
Private Sub timer_Tick(ByVal sender As Object, ByVal e As EventArgs)
'Calling refresh after 1 second and updating the data
Me.DataGridView1.Refresh()
Me.View1TableAdapter.Fill(Me.XYZDataSet.view1)
End Sub
End Class
I've solved a similar problem in the past by storing the indexes of the selected cell in a variable before doing the refresh, so I'm able to restore the selection by calling DataGridView.Rows(selRow).Cells(selCol).Selected = True after the update.
Edit - Sample Code:
To later readers:Please take a look at Edit#2 where I describe a better method to re-select the previous selected cell!
Sample Code:
' Variables for remembering the indexes of the selected cell
Dim selRow As Integer
Dim selCol As Integer
' Check if there is a selected cell to prevent NullPointerException
If DataGridView1.SelectedCells().Count > 0 Then
selRow = DataGridView1.CurrentCell.RowIndex
selCol = DataGridView1.CurrentCell.ColumnIndex
End If
' Dummy "update"
' don't forget to clear any existing rows before adding the new bunch (only if you always reloading all rows)!
DataGridView1.Rows.Clear()
For index = 1 To 20
DataGridView1.Rows.Add()
Next
' Check if there are "enough" rows after the update,
' to prevent setting the selection to an rowindex greater than the Rows.Count - 1 which would
' cause an IndexOutOfBoundsException
If (DataGridView1.Rows.Count - 1) > selRow Then
' Clear selection and then reselect the cell that was selected before by index
DataGridView1.ClearSelection()
' For the next line of code, there is a better solution in Edit #2!
DataGridView1.Rows(selRow).Cells(selCol).Selected = True
End If
Please note:
This procedure requires you to add the rows in the exact same order that you have added them before the update, as only the .Index of the selected row is stored in the variable. If you readding the rows in a different order, then not the same row but the row at the same position will be selected after the refresh.
You should add check if there is a selected row at all (to prevent a NullPointerException) and if there are "enough" rows in the DataGridView after the refresh, to prevent an IndexOutOfBoundsException.
This only works if the DataGridView1.SelectionMode is to something that actually selects rows, like FullRowSelect.
Don't forget to clear any existing rows before adding new ones by updating (only if you always reloading all rows).
Edit 2 - RowHeader triangle and accidental MultiSelect
As stated in the comments below, there was an odd behavior that would lead to an accidental MultiSelect, if the user holds down the mouse button past the refresh cycle. Also, the RowHeader triangle was not set to the correct row.
After some research I found a solution to this behavior. Instead of setting the .Selected-property of a given cell to True, set the .CurrentCell-property of the DataGridView to the cell you would like to select!
In code, this means changing
DataGridView1.Rows(selRow).Cells(selCol).Selected = True
to
DataGridView1.CurrentCell = DataGridView1.Rows(selRow).Cells(selCol)
and there you go. :-)
Before Fill, store the CurrentRow values and currenCell column:
Dim currentColumnIndex As Integer = 0 ;
Dim currentValues As List(Of Object) = If(DataGridView1.CurrentRow Is Nothing, Nothing, New List(Of Object)())
If currentValues IsNot Nothing Then
For i As Integer = 0 To DataGridView1.Columns.Count - 1
currentValues.Add(DataGridView1.CurrentRow.Cells(i).Value)
Next
currentColumnIndex = DataGridView1.CurrentCell.ColumnIndex;
End If
After Fill, search the row corresponding to stored values:
Dim i As Integer = 0
While i < DataGridView1.Rows.Count AndAlso currentValues IsNot Nothing
Dim areIdentical As Boolean = True
Dim j As Integer = 0
While j < DataGridView1.Columns.Count AndAlso areIdentical
areIdentical = DataGridView1.Rows(i).Cells(j).Value = currentValues(j)
j += 1
End While
If areIdentical Then
DataGridView1.CurrentCell = DataGridView1.Rows(i).Cells(currentColumnIndex)
currentValues = Nothing
End If
i += 1
End While
Note: the "For/While" loop coding is perhaps not optimal because it results from automatic conversion from C# to vb.net.
C# fix code , next reload pattern
if (dataGridView7.SelectedCells.Count > 0)
{
//MessageBox.Show(selcell + "------"+dataGridView7.CurrentCell.ColumnIndex.ToString());
if (selcell > 0 && dataGridView7.CurrentCell.ColumnIndex==0) { }else
{
selrow = dataGridView7.CurrentCell.RowIndex;
selcell = dataGridView7.CurrentCell.ColumnIndex;
}
}
loaddataJobsall();
dataGridView7.ClearSelection();
dataGridView7.Rows[selrow].Cells[selcell].Selected = true;

How To Clear CheckedListBox From Previous Selection - VB.NET

Okay so I have a checkedlistbox that when a user selects a item it will print out that item into word. That works perfect. However, I want to give the user the option to not select anything at all, but when the user does not select an item in the checkboxlist, it still prints out the previous selected item into MS word.
Below is my code:
Private Sub ExportContactOkButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExportContactOkButton.Click
Dim i As Integer
Dim array_Counter_Contacts As Integer
Dim array_size_Contacts As Integer
array_Counter_Contacts = 0
For i = 0 To ExportContactCheckedListBox.Items.Count() - 1
If ExportContactCheckedListBox.GetItemCheckState(i) = CheckState.Checked Then
array_size_Contacts = UBound(SelectedContacts)
ReDim Preserve SelectedContacts(array_size_Contacts + 1)
SelectedContacts(array_Counter_Contacts) = ExportContactCheckedListBox.Items(i)
If Search.debugging = True Then
MsgBox(ExportContactCheckedListBox.Items(i))
End If
array_Counter_Contacts += 1
ExportContactCheckedListBox.Items(i) = ExportContactCheckedListBox.Items(i).ToString.Replace("'", "''")
If array_Counter_Contacts = 1 Then
ContactNames = "" & ExportContactCheckedListBox.Items(i) & ""
Else
ContactNames = String.Concat(ContactNames & "', '" & ExportContactCheckedListBox.Items(i) & "")
End If
End If
Next
If Search.debugging = True Then
MsgBox(ContactNames)
End If
sConnection.Close()
Dispose()
Me.Close()
End Sub
I have tried remove, clear, and I even tried this
Dim i As Integer
For i = 0 To ExportContactCheckedListBox.CheckedIndices.Count - 1
ExportContactCheckedListBox.SetItemChecked(ExportContactCheckedListBox.CheckedIndices(0), False)
Next i
But nothing is working. Can anyone help me? All I want is to be able to have the checkedlistbox forget or clear the checked item after the "OK" button is pressed and the text has already been printed into word.
Use a List(Of String) to store the selection and, of course remember, to reinitialize the list when you hit the ExportContactOkButton
' Declared at the form level....
Dim SelectedContacts as List(Of String)
.....
Private Sub ExportContactOkButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExportContactOkButton.Click
Dim i As Integer
SelectedContacts = new List(Of String)()
For i = 0 To ExportContactCheckedListBox.Items.Count() - 1
If ExportContactCheckedListBox.GetItemCheckState(i) = CheckState.Checked Then
SelectedContacts.Add(ExportContactCheckedListBox.Items(i))
.....
End If
Next
End Sub
In this way, every time you hit the ExportContactOKButton you reinitialize your list of contacts, loop through the checked items, add the checked one to your list.
A List(Of String) is better because you don't need to know in advance how many items your user selects in the CheckedListBox and continuosly resize the array. You simply add new items to it. And you could always use it like an array
Dim Dim array_Counter_Contacts = SelectedContacts.Count
For i = 0 to array_Counter
Console.WriteLine(SelectedContacts(i))
Next

Listbox Multiple KeyPress

How can I achieve the search functionality that works with multiple keys in CheckedListBox and ListBox?
Example: I have the following items in the list:
1000
1500
1520
2010
5001
5102
When I press the key 1, instantly search the first hit that match with the first char that starts with '1'.
But, If I want locate the item "5102", the list only will can search the 5, and then, I need go manually to identify the wanted item.
Answering to my own question. This it's a clean solution that doesn't need too much work (All the code can handle in the KeyDown event):
Sub DropDownListBox_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
If Char.IsLetterOrDigit(Chr(e.KeyValue)) Then
e.SuppressKeyPress = True
If TryCast(sender.tag, Timer) Is Nothing Then
Dim vTimer As New Timer
vTimer.Interval = 1000
vTimer.Tag = ""
sender.Tag = vTimer
AddHandler vTimer.Tick,
Sub(Timer As Object, eventsArgs As System.EventArgs)
Timer.Tag = ""
If Not TryCast(sender, CheckedListBox).Visible Then
Timer.dispose() : Timer = Nothing
End If
End Sub
Else
sender.Tag.Stop() : sender.Tag.Start()
sender.Tag.Tag &= Chr(e.KeyValue)
Dim vIndex As Integer = TryCast(sender, CheckedListBox).FindString(sender.Tag.Tag)
If vIndex <> -1 Then TryCast(sender, CheckedListBox).SelectedItem = TryCast(sender, CheckedListBox).Items(vIndex)
End If
End If
End Sub
Basically I use the TAG object to keep a Timer running every 1 sec; then, if the user typing several chars, the process will find exactly the wanted text.
Any comment or feedback will be welcome.
Public Class Form1
Dim Type As String
Private Sub ListBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles ListBox1.KeyPress
If Asc(e.KeyChar) <> 8 Then
If Asc(e.KeyChar) < 65 Or Asc(e.KeyChar) > 122 Then
e.Handled = True
' Clear String at Escape key press & Reset Listbox location
If Asc(e.KeyChar) = 27 Then
Type = ""
ListBox1.SelectedIndex = -1
ListBox1.SelectedItem = ListBox1.SelectedIndex
End If
End If
If Asc(e.KeyChar) = 27 Then
' Do not add escape key char to string at key press
Else
' add char one by one after key press
Type &= e.KeyChar
Dim TL As Integer = Type.Length
Dim i As Integer = 0
For i = 0 To ListBox1.Items.Count - 1
' match key press in total items in listbox
'MsgBox(Format$(Mid$(ListBox1.Items(i), 1, TL)))
If Format$(Mid$(ListBox1.Items(i), 1, TL)) = Type Then
ListBox1.SelectedIndex = i
End If
Next
End If
End If
End Sub
End Class

Programmatically change selection on DatagridView (.NET)

I'm learning VB.NET.
I've a problem with DataGridView component when trying to set the value of the CurrentCell.
What i'm trying to do is :
I've a DataGridView With values.
I want to make a button in my forms and when clicking on it I want to change the selection from the current row to the next. To explain more, by clicking my Button I want to simulate the effect of a mouse click on a DataGridview.
I hope you can help me,
Thanks!
Maybe something like this:
If DataGridView1.RowCount > 0 Then
Dim MyDesiredIndex As Integer = 0
If DataGridView1.CurrentRow.Index < DataGridView1.RowCount - 1 Then
MyDesiredIndex = DataGridView1.CurrentRow.Index + 1
End If
DataGridView1.ClearSelection()
DataGridView1.CurrentCell = DataGridView1.Rows(MyDesiredIndex).Cells(0)
DataGridView1.Rows(MyDesiredIndex).Selected = True
End If
Note 1: maybe these two lines are not necessary. I havenĀ“t proved it
DataGridView1.ClearSelection()
DataGridView1.CurrentCell = DataGridView1.Rows(MyDesiredIndex).Cells(0)
Note 2: note that if we are in the last row, it goes to first
You need to set the particular row's Selected property to true. I think the VB would be something like this:
someDGV.Rows(index).Selected = True
If your data grid is bound to a BindingSource, it is better to change the position there:
Object key = Convert.ToInt32(cdr["WordList"]);
int itemFound = lexiconNamesBindingSource.Find("ID_Name", key);
lexiconNamesBindingSource.Position = itemFound;
...and you might need to finish it off with:
lexiconNamesBindingSource.ResetBidings();
(This is an old thread, but I found it, so someone else might find this useful)
Just use the BindingSource.MoveNext() and BindingSource.MovePrevious() methods.
You could do it this way:
If DataGridView1.CurrentRow.Index < DataGridView1.Rows.Count Then
DataGridView1.Rows(DataGridView1.CurrentRow.Index + 1).Selected = True
End If
To get the selected row, you should use SelectedRows(0).Index inspite of CurrentRow. Because if you programmaticaly make a row as selected, then next time you will find 0 in CurrentRow.Index. So It would be like :
If DataGridView1.SelectedRows(0).Index < DataGridView1.RowCount - 1 Then
MyDesiredIndex = DataGridView1.SelectedRows(0).Index + 1
End If
DataGridView1.Rows(MyDesiredIndex).Selected = True
expanding on the answer above which is perfect considering I spent at least 4 hours loooking for this.
and assuming that your datagridview is called dgvDevices... this code will handle the event in which you go outbounce as you move back and forward on your rows
Private Sub btnPrev_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrev.Click
Try
dgvDevices.ClearSelection()
Dim currentr As Integer = dgvDevices.CurrentCell.RowIndex
dgvDevices.CurrentCell = dgvDevices.Rows(currentr - 1).Cells(0)
dgvDevices.Rows(currentr - 1).Selected = True
Catch ex As Exception
dgvDevices.CurrentCell = dgvDevices.Rows(0).Cells(0)
dgvDevices.Rows(0).Selected = True
End Try
End Sub
Private Sub btnForw_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnForw.Click
Try
dgvDevices.ClearSelection()
Dim currentr As Integer = dgvDevices.CurrentCell.RowIndex
dgvDevices.CurrentCell = dgvDevices.Rows(currentr + 1).Cells(0)
dgvDevices.Rows(currentr + 1).Selected = True
Catch ex As Exception
dgvDevices.CurrentCell = dgvDevices.Rows(dgvDevices.RowCount - 1).Cells(0)
dgvDevices.Rows(dgvDevices.RowCount - 1).Selected = True
End Try
End Sub
Besides Javiers correct answer, if you're using BindingSource for your datagridview then it will be better to change selected item from binding source rather than using datagridview.CurrentCell:
' Example Definitions
Dim bsExample As New BindingSource
Dim dgv As New DataGridView
dgv.DataSource = bsExample
' Example code to change current row position
Dim desiredIndex As Integer = 10
bsExample.Position = desiredIndex
Private Sub DGW2_DataBindingComplete(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewBindingCompleteEventArgs) Handles DGW2.DataBindingComplete
Dim mygrid As DataGridView
mygrid = CType(sender, DataGridView)
mygrid.ClearSelection()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If DataGridView1.Rows.Count - 1 > 0 Then
For i As Integer = 0 To DataGridView1.Rows.Count - 1 Step +1
If DataGridView1.Rows.Count - 1 > 0 Then
DataGridView1.Rows.RemoveAt(0)
End If
Next
Else
End If
End Sub
Easy with Extensions
Imports System.Runtime.CompilerServices
Module Extensions
''' <summary>
''' Select the Row(Index)
''' </summary>
''' <param name="Dgv">The DataGridView</param>
''' <param name="Index">The Row Index (0 First)</param>
''' <param name="ScroolToTop">If True scrool the row to top</param>
''' <returns>True if no error or False if something went wrong</returns>
' USE: if not DataGridView1.GoToRow(30) then MsgBox("Something went wrong!)
<Extension()>
Public Function GoToRow(Dgv As DataGridView, Index As Integer, Optional ScroolToTop As Boolean = True) As Boolean
If Index > -1 And Index < Dgv.Rows.Count - 1 Then
With Dgv
.ClearSelection()
.Rows(Index).Selected = True
If ScroolToTop Then .FirstDisplayedScrollingRowIndex = Index
End With
Return True
End If
Return False
End Function
End Module
I have DataGridView like that :
| ID | Name |
|:---|:-----:|
| 1 | Samir |
I search by 'Name' using this code :
Private Sub GunaButton6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GunaButton6.Click
Dim temp As Integer = 0
For i As Integer = 0 To Me.Listofclient.RowCount - 2
If Me.Listofclient.Rows(i).Cells(1).Value.ToString = EDSearch.Text Then
Me.Listofclient.ClearSelection()
Me.Listofclient.Rows(i).Selected = True
temp = 1
End If
Next
If temp = 0 Then
MsgBox("Item not found")
End If
End Sub