Go next in datagridview [duplicate] - vb.net

This code
CurrentSelectedRow = Me.dgvPreviouslyCut.CurrentRow.Index
stores the current selected row that has been clicked by the user in a data grid view control .
After refreshing the datasource for the data grid view, this code
Me.dgvPreviouslyCut.Rows(CurrentSelectedRow).Selected = True
programmatically re-selects the same row.
Immediately afterwards though
Me.dgvPreviouslyCut.CurrentRow.Index
is always set to zero, NOT the variable CurrentSelectedRow as you would expect.
Why does programmatically setting the select row index not cause the property CurrentRow.Index to be set to the same?

CurrentRow is the row containing the currently active cell. When you bind the DataGridView to an external data source, this property is reset to its default value which is the first cell in the first column.
SelectedRow is the row which is currently selected/highlighted. It may be one or more rows depending on MultiSelect property. To select a row you have to set its Selected property to true.
By setting the row as selected you merely keeping it highlighted not making it active.
To retain the current cell you have to store the Current cell's row and column index. To get them use the CurrentCellAddress property. Once your refresh the DataSource set the CurrentCell property using these indexes.
dataGridView1.CurrentCell = dataGridView1.Rows(rowindex).Cells(columnindex);

The DataGridView creates a new CurrencyManager when the data source is changed. If this CM contains items, the default position is 0, thus pushing this to the DGV and selects the first row.
To fix this, just set the position of the CM instead:
Me.dgvPreviouslyCut.DataSource = my_new_datasource
Dim cm As CurrencyManager = CType(Me.BindingContext(my_new_datasource), CurrencyManager)
If ((Me.CurrentSelectedRow > -1) AndAlso (Me.CurrentSelectedRow < cm.Count)) Then
cm.Position = Me.CurrentSelectedRow
End If

Related

How to get the real row's height in a DataGridView?

I'm using a TabControl to insert DataGridView in each tab. The first Column of the DGV is a ButtonCollumn and I'm trying to change the padding of all cell in this first column in each DGV by using the row's height (so that all the button can be the same size), but the height is different from the one showned. It works correctly for the first Tab, but not the others.
I have tried to do the change the padding at different place in my code, in case the height may somehow not be set yet, but nothing changed.
I have set the grid's RowTemplate to a minimum. This same minimum is the one that i see when i look at the height of each row of any other tab than the first. So in the end, the padding is wrong and the button oversized.
I thought it might be because of the DGV not being drawn at that moment so the size wouldn't be set yet, but the first Tab makes me believe otherwise.
Here's my code for the padding, if it can be of any help:
For each tp As TabPage In Me.TabControl1.TabPages
Dim dgv As DataGridView = tp.Controls(0)
For each row as DataGridViewRow In dgv.Rows
dim h As integer = row.Height
row.Cells(0).Style.Padding = New Padding(12,
Math.Ceiling((h -24)/2),
12,
Math.Floor((h -24)/2))
row.Cells(0).Value = h ' For debbuging purpose
Next
Next
Edit:
When I create the DGV, the AutoSizeRowsMode is set to AllCells, WrapMode to True. (If this info can help)

Revert DataGridView cell contents to original value

(I have rephrased this entire question in an attempt to be more clear in what I'm trying to do)
This is a VB.Net WinForms project being written in VS2012.
When the user changes the contents of a DataGridView's cell, I am changing the background color of the cell to visually indicate to the user which cells they have changed. That works fine.
However, if the user changes the cell contents back to what the value was before they initially edited it (essentially what the database table's value is), I need to change the background color to its default row background color.
So, in the CellValidating event I am using the following lines to get the value from the DataGridView's bound dataset and the value that the user entered so I can compare the two:
Dim dgvColDataName As String = dgvEmployees.Columns(e.ColumnIndex).DataPropertyName
Dim dgvRowID As Integer = CInt(dgvEmployees.Rows(e.RowIndex).Cells(1).Value)
Dim index As Integer = EmployeesDataSet.Tables("employees").Rows.IndexOf(EmployeesDataSet.Tables("employees").Rows().Find(dgvRowID))
Dim originalValue As String = EmployeesDataSet.Tables("employees").Rows(index).Item(dgvColDataName).ToString()
Dim enteredValue As String = dgvEmployees.Rows(e.RowIndex).Cells(e.ColumnIndex).EditedFormattedValue.ToString()
These get the correct, corresponding values between the DataGridView's current cell and its corresponding cell in the bound table.
Here is where I am comparing the values to determine if the value entered is the same as the original dataset's value:
If originalValue.ToUpper() <> enteredValue.ToString().ToUpper() Then
' Color the edited cell's background
dgvEmployees.Rows(e.RowIndex).Cells(e.ColumnIndex).Style.BackColor = Color.LightPink
Else
' Set the back color to its default style
dgvEmployees.Rows(e.RowIndex).Cells(e.ColumnIndex).Style.BackColor = dgvEmployees.Rows(e.RowIndex).Cells(e.ColumnIndex).InheritedStyle.BackColor
End If
I thought this was the answer. The cell background is being changed when the value is changed. But I was surprised to discover that if the cell loses focus (leaves Edit Mode) and then the user clicks back in that cell and changes the value to what it originally was before initially editing it, the cell back color doesn't change back to the default row/cell color. I.e. apparently when the cell loses focus, the dataset is changed, so originalValue is now the last entered value.
I need to be able to get the value from when the DataGridView was first loaded or after the last save.
Any ideas?
UPDATE
After some more research I was able to figure out how to access the DataSet's original, pre-editing value of a given cell.
In the variable assignment code above I added this line to get the relevant DataSet row:
Dim row As DataRow = EmployeesDataSet.Tables("employees").Rows(dsRowIndex)
Then I replaced this line:
Dim originalValue As String = EmployeesDataSet.Tables("employees").Rows(index).Item(dgvColDataName).ToString()
with this:
Dim originalValue As String = row(dgvColDataName, DataRowVersion.Original).ToString()
So after thoroughly testing this I am confident that, regardless of the state of the DGV, editing controls, etc. the originalValue will be the value that came from the database table.
I'm marking this as answered...
The below code will accomplish what I was trying to do. This is in the CellValidating event. I am using it to set the value back to the original cell value as it was coming from the database.
Dim dgvColDataName As String = dgvEmployees.Columns(e.ColumnIndex).DataPropertyName
Dim dgvRowID As Integer = CInt(dgvEmployees.Rows(e.RowIndex).Cells(1).Value)
Dim dsRowIndex As Integer = EmployeesDataSet.Tables("employees").Rows.IndexOf(EmployeesDataSet.Tables("employees").Rows().Find(dgvRowID))
Dim row As DataRow = EmployeesDataSet.Tables("employees").Rows(dsRowIndex)
Dim originalValue As String = row(dgvColDataName, DataRowVersion.Original).ToString()

How do I keep the same row selected in a datagridview after refreshing the dataset?

This code is called from a timer tick event so that the dataviewgrid refreshes at frequent intervals.
From other answers I found on SO I would expect this code to reset the selected row to the row that was selected before this code runs, refreshing my dataset.
Only the variable CurrentSelectedRow is a public variable, all others are local.
sql = "select top 10 batch, TrussName, PieceName from FitaPieces order by SawTime desc "
myDataset = SelectFromDB(sql)
MyPreviouslyCutPieces.ClearAll()
Me.dgvPreviouslyCut.SelectionMode = DataGridViewSelectionMode.FullRowSelect
If Not IsNothing(Me.dgvPreviouslyCut.CurrentRow) Then
Debug.Print(Now.ToString & "...Current Row = " & Me.dgvPreviouslyCut.CurrentRow.ToString)
CurrentSelectedRow = Me.dgvPreviouslyCut.CurrentRow.Index
Else
Debug.Print(Now.ToString & "...Current Row = -1")
CurrentSelectedRow = -1
End If
If Not myDataset Is Nothing Then
If myDataset.Tables("CurData").Rows.Count > 0 Then
Me.dgvPreviouslyCut.DataSource = myDataset
Me.dgvPreviouslyCut.DataMember = "CurData"
End If
End If
If CurrentSelectedRow <> -1 Then
Me.dgvPreviouslyCut.Rows(0).Selected = False
Me.dgvPreviouslyCut.Rows(CurrentSelectedRow).Selected = True
End If
And it does..for the first tick of the timer event. On the second tick event after the user selects a row, it reverts back to the first row being selected. Even though the variable CurrentSelectedRow is a public variable, it's getting reset to zero after the first tick event. Then the selected row switches back to the first row in the grid. The first row is auto selected when you refresh a grid's datasource, but I'm setting it's selected status to false after the refresh.
How is the dataviewgrid's selected row getting reset to the first row?
Grab the current index and store it in a variable called "go_back_to_index"
Dim go_back_to_index as integer
when the user clicks on the row in the grid, just save the value so you can highlight it later:
go_back_to_index = current_data_grid.currentRow.value
then when the grid is updated, just run this piece of code:
If go_back_to_index < current_data_grid.Rows.Count Then
current_data_grid.Rows(go_back_to_index).Selected = True
current_data_grid.CurrentCell = current_data_grid.Item(1, go_back_to_index)
End If
Remember to make sure you set up your datagrid so the whole row is highlighted when a cell is clicked on.
The reason why this is happening is because you're changing the DataSource of the grid in every cycle.
The best way (but the hardest way) to solve this is to run the DataGridView in VirtualMode.
If not, one should set the data source only once. And when you need to update the table, merge the table bound to the grid with the new table.
DirectCast(Me.dgvPreviouslyCut.DataSource, DataTable).Merge(myDataset.Tables("CurData"))
If you can't seem to get the DataGridView to work. Try a different control until you do get the problem solved. I have personally used a listbox to achieve the same thing.

in vb.net, how do i exclude a column from being highlighted with a datagridview?

I have a datagridview set up and I have set one of the properties to
.SelectionMode = DataGridViewSelectionMode.FullRowSelect
which is what I want, but the last col of the row is a button column and the button also gets highlighted with the rest of the row. I do not want the button highlighted. I have tried setting the last col's properties to read only, and others and nothing worked. I also set up a handler to listen for when the row was highlighted and then deselected the last col, but that just deselected the whole row.
Does anyone know how to un-highlight just the last column of buttons?
Thanks.
Try hooking into OnRowSelected event and then making the last column not selected.
In the designer(or through code) set next properties:
ButtonColumn.DefaultCellStyle.BackColor = System.Drawing.Color.White
ButtonColumn.DefaultCellStyle.ForeColor = System.Drawing.Color.Black
ButtonColumn.DefaultCellStyle.SelectionBackColor = System.Drawing.Color.White
ButtonColumn.DefaultCellStyle.SelectionForeColor = System.Drawing.Color.Black
This will set column colors(BackColor and ForeColor) to the same color for the both states(normal and selected).
So when row became selected current column doesn't change color...

figure out rowindex on a row I just inserted?

I've got a vb project I am updating and it has a datagridview, a panel, and buttons along the bottom. The buttons control CRUD operations. The panel shows numerical up/downs and textboxes to represent the selected row.
I use some logic to keep track of current selected row and current row index for timer updates in the background. Upon delete I reset focus on the first row. Upon loading I set focus on first row. On update I keep current row focus.
Upon a good insert I would like to set the focus to the row I just inserted. But I do not know a way to determine what the rowindex value is for this freshly inserted row. My datatable which the datagridview uses is sorted on two id columns so it's not like the new entry will just jump to the bottom.
Any ideas on how I can implement this?
If you don't want to deal with the RowAdded event as Jay Riggs suggested, if you add it using a row object, as opposed to just Rows.Add, you should be able to pull that off of the row object after it's inserted.
Dim dgr As New DataGridViewRow()
DataGridView1.Rows.Add(dgr)
Me.DataGridView1.Rows.IndexOf(dgr)
This should also work for insert as well.
Check out the DataGridView RowAdded event; its DataGridViewRowsAddedEventArgs parameter includes the RowIndex property which gives you what you need.
The event fires everytime a row is added, so you'll have to either wire the event up when you want to check for added rows, or ignore the event when you don't care when a row is added (such as when your grid fills with data).
If you manually add rows to the DataGridView, then you can just use the return value from the Add method. Examples:
Dim newRowIndex As Integer = myDataGridView.Rows.Add()
myDataGridView.Rows(newRowIndex).Selected = True
No need to call IndexOf. If the DataGridView is bound to a DataSource then Jay Riggs' solution of using the RowsAdded event is the way to go.