Why is gridview.selectedColumns nothing? - vb.net

I want to run a code like this, but it always jumps over the loop, so I see no line in the console.
That means that selectedColumns is empty. My assumption was that I (or the user) select a cell from a Column and then, selectedColummns are +1. But as it looks, it doesnt work. Then I tried to set proberties of selectionMode to select full columns, but then an exception is thrown:
"System.InvalidOperationException" Additional Information: the SortMode cannot be Automatic, if full Column selection is selected.
I don't know what SortMode is.
For Each col As DataGridViewColumn In datagridview2.SelectedColumns
Console.Write(datagridview2.SelectedColumns.Count)
Console.Write("1")
Next
Any Ideas how to get that the columns into selectedColumns?
Here my code that solved my problem, but I guess it is not the smartest one:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim body As String = ""
Dim myWriter As New StreamWriter("H:\downloads\test.csv", True)
Dim list As List(Of Integer) = New List(Of Integer)
For Each cell As DataGridViewCell In datagridview2.SelectedCells
If list.Contains(cell.ColumnIndex) = False Then
list.Add(cell.ColumnIndex)
End If
Next
For i = 0 To datagridview2.Rows.Count - 1
For ix = 0 To datagridview2.Columns.Count - 1
If list.Contains(ix) Then
If datagridview2.Rows(i).Cells(ix).Value IsNot Nothing Then
body = body + datagridview2.Rows(i).Cells(ix).Value.ToString + ";"
Else
body = body + ";"
End If
End If
Next
myWriter.WriteLine(body)
body = ""
Next
myWriter.Close()
End Sub

You need to do this after the selected changed event has fired.
For example:
Private Sub Mydg_ColSelected(sender As Object, e As SelectionChangedEventArgs) Handles datagridview2.SelectionChanged
For Each col As DataGridViewColumn In datagridview2.SelectedColumns
Console.Write(datagridview2.SelectedColumns.Count)
Console.Write("1")
Next
End Sub
Or if this isn't what you are after, then try handling the ColumnHeaderMouseClick event instead. I'm not sure what technology you are using, e.g Winforms, WPF, silverlight

Related

Add CheckBox To DataGridView Cell Programmatically

I’m trying to add a CheckBox programmatically to a DataGridVew cell if the cell next to it has a value of “1”. I’m trying to do this as the rows are added
I’m hoping someone can help me out with the correct code here. I understand one of the lines of code is incorrect but I’ve put it in to illustrate what I'm trying to do.
Thanks in advance.
Private Sub Controls_DGV_RowsAdded(sender As Object, e As Windows.Forms.DataGridViewRowsAddedEventArgs) Handles Controls_DGV.RowsAdded
If Controls_DGV.Rows(e.RowIndex).Cells(2).Value = "1" Then
Controls_DGV.Rows(e.RowIndex).Cells(1).AddCheckBox ' THIS LINE IS INCORRECT
End If
End Sub
This is the same as #miguel except for the checking the value, in this case Option Strict is On as it should be.
Public Class Form1
Private Sub dataGridView1_RowsAdded(sender As Object, e As DataGridViewRowsAddedEventArgs) _
Handles dataGridView1.RowsAdded
If CStr(dataGridView1.Rows(e.RowIndex).Cells(1).Value) <> "1" Then
dataGridView1.Rows(e.RowIndex).Cells(0).Value = False
dataGridView1.Rows(e.RowIndex).Cells(0) = New DataGridViewTextBoxCell()
dataGridView1.Rows(e.RowIndex).Cells(0).Value = ""
dataGridView1.Rows(e.RowIndex).Cells(0).ReadOnly = True
End If
End Sub
Private Sub AddRowsButton_Click(sender As Object, e As EventArgs) _
Handles AddRowsButton.Click
For index As Integer = 0 To 5
If CBool(index Mod 2) Then
dataGridView1.Rows.Add(False, "0")
Else
dataGridView1.Rows.Add(False, "1")
End If
Next
End Sub
End Class
The column number 1 that you want to display a checkbox should already be of type DataGridViewCheckBoxColumn and then if the value is not "1" you can transform the type of the cell for a DataGridViewTextBoxCell, so there is no checkbox and you can even put there some text if you want. Because you're using 3 columns, i'll try to do the same.
In your Form1_Load() you should have something like this if you are adding columns programmatically:
Dim ChkBox As New DataGridViewCheckBoxColumn
Controls_DGV.Columns.Add("TextBox1", "TextBox1")
Controls_DGV.Columns.Add(ChkBox)
Controls_DGV.Columns.Add("TextBox2", "TextBox2")
Then using your code it should be like this:
Private Sub Controls_DGV_RowsAdded(sender As Object, e As Windows.Forms.DataGridViewRowsAddedEventArgs) Handles Controls_DGV.RowsAdded
If Controls_DGV.Rows(e.RowIndex).Cells(2).Value <> "1" Then
' replace the checkbox cell by textbox cell
Controls_DGV.Rows(e.RowIndex).Cells(1) = New DataGridViewTextBoxCell()
Controls_DGV.Rows(e.RowIndex).Cells(1).Value = "(empty or some text)"
End If
End Sub

Read and write below a precise cell in a CSV

I'm stuck on a basic problem. What I want is to parse through a CSV in order to compare some string and write below if I find it.
Precisely, I have a programe where I can drag and drop some button, when I drop this button I want to save it's new location on the first empty cells below the corresponding column.
Here's a sample of my CSV :
So I substring the .x/.y from my CSV and compare the name from the drop button with each cell with the help of textFieldParser. It seems to work my loop stopped when it find an equal expression.
But here's the problem I don't know how to say to my program to write below it. The first reason I can figured it out is because my parser go until the endOfData and I want it to go until the endOfDat + one row.
The second one is because I don't know if I can use a fieldwriter into textFieldParser, I mean I tried to create a variable with row+1 and write below but nothing happen when I use fileWriter.
now a sample of my code :
Private Sub manageCsv(ByVal sender As Button)
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser("..\..\Pic\csvPic.csv")
MyReader.TextFieldType = FileIO.FieldType.Delimited
MyReader.SetDelimiters(",")
Dim currentRow As String()
Dim rowPlusOne As String()
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
rowPlusUn = MyReader.ReadFields()
Dim currentField As String
Dim str As String = btnSender.Name.Substring(3)
Dim nameDelimited As String
Dim x As Integer
For Each currentField In currentRow
''Search the corresponding field''
x = InStr(currentField, ".")
If Not (currentField.Equals("imagefile")) Then ''imagefile is the first index of my csv''
nameDelimited = currentField.Substring(0, x) ''substr the extension''
If nameDelimited.Equals(str) Then
writeCsv("..\..\Image\csvPic.csv", nameDelimited, ",")
''Ofc the "+1" does not work but that was the idea''
currentRow(+1) = lblImgName.Text
currentRow(+1) = btnSender.Location.ToString
Exit For
End If
End If
Next
Catch ex As _
Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message & "is not valid and will be skipped.")
End Try
End While
End Using
End Sub
I hope it's clear enough, if not i'll try to elaborate more. Thanks for your help
Show your teacher that there are better ways to do this with a simple text file. The file will only exist if buttons have been moved before in the application. See in line comments.
Private ButtonLocation As New Dictionary(Of Button, Point)
Private MouseIsDown As Boolean
Private ptX, ptY As Integer 'Starting point of mouse relative to the button
Private btn As Button 'The button being moved
Private ButtonPath As String = "C:\Users\maryo\Desktop\Code\DroppedButtons.txt"
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Reposition the buttons to where they were dropped in the previous session.
If File.Exists(ButtonPath) Then
Dim lines = File.ReadAllLines(ButtonPath) 'returns an array of strings (each line)
For Each line In lines 'loop though each line in the file
Dim fields = line.Split(","c) 'The three values on the line are separated by a comma
Dim b = DirectCast(Controls(fields(0)), Button) 'Change the string Button.Name
'to an actual Button object by finding it in the controls collection
'Set the location with the next 2 values on the line
b.Location = New Point(CInt(fields(1)), CInt(fields(2)))
'Add the Button and Location to the list
ButtonLocation.Add(b, b.Location)
Next
End If
End Sub
'These three Event procedures are the normal code to Drag and Drop a control
Private Sub Button_MouseDown(sender As Object, e As MouseEventArgs) Handles Button1.MouseDown, Button2.MouseDown
btn = DirectCast(sender, Button)
ptX = e.Location.X
ptY = e.Location.Y
MouseIsDown = True
End Sub
Private Sub Button_MouseMove(sender As Object, e As MouseEventArgs) Handles Button1.MouseMove, Button2.MouseMove
If MouseIsDown Then
'e.X and e.Y are the coordinates of the Mouse relative to the control (the Button)
'not the Form or the Screen.
btn.Location = New Point(btn.Location.X + e.X - ptX, btn.Location.Y + e.Y - ptY)
End If
End Sub
Private Sub Button_MouseUp(sender As Object, e As MouseEventArgs) Handles Button1.MouseUp, Button2.MouseUp
MouseIsDown = False
'When we drop the button with the MouseUp event we record the new location in the list
RecordButtonLocation(btn, btn.Location)
btn = Nothing
End Sub
Private Sub RecordButtonLocation(Sender As Button, Location As Point)
'Check if the Button is already in the list
If ButtonLocation.ContainsKey(Sender) Then
'Record its new location
ButtonLocation.Item(Sender) = Location
Else
'If it is not in the list add it.
ButtonLocation.Add(Sender, Location)
End If
End Sub
Private Sub Form1_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Me.Closing
SaveDictionary()
End Sub
Private Sub SaveDictionary()
If ButtonLocation.Count > 0 Then
'If there is anything in the list we will create or overwrite the file
Dim sb As New StringBuilder
For Each kv As KeyValuePair(Of Button, Point) In ButtonLocation
sb.AppendLine($"{kv.Key.Name},{kv.Value.X},{kv.Value.Y}")
Next
File.WriteAllText(ButtonPath, sb.ToString)
End If
End Sub

How to pass the 2nd selected row in datagridview to textbox?

How do i pass my 2nd selected row in datagridview to textboxt. I only know how to put the first data. How do i pass the 2nd selected to textbox?
Dim i As Integer
i = DataGridView2.SelectedRows(0).Index
Me.txtEmployeeID.Text = DataGridView2.Item(0, i).Value
you can use this code it worked for me
Dim test As String = DataGridView1.SelectedRows(0).Cells(2).Value.ToString
You need to only change the .cell(Here write the index value of the cell)
Then you can use the string value to fill up textbox
Try using the following:
Dim secondRow as integer = 0
Private Sub DataGridView2_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView2.CellClick
'assuming that by second selected row, you mean the row after the selected row
secondRow = e.RowIndex + 1
End Sub
Private Sub RowToTextBox()
Try
For i = 0 to DataGridView2.ColumnCount - 1
txtEmployeeID.Text &= DataGridView2.Item(i, secondRow)
Next
Catch ex as Exception
MsgBox("You have selected the final row")
End Try
End Sub
I don't think Me. is needed when referring to a textbox in the same form.
Since you don't know how many rows your user will select, I think looping thought the SelectedRows collection might work. I used the Name column because that is what I happened to have in my grid. Instead of a MessageBox you could add the values to a ListBox.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
For Each GridRow As DataGridViewRow In DataGridView1.SelectedRows
MessageBox.Show($"Value is {GridRow.Cells("Name").Value}")
Next
End Sub

dgv add row number to headercell

I'm trying to show the rownumber of a datagridview in the headercell I was under the impression that this was possible but I can't get it to show the value.
What do I need to do?
** The dgv is bound with BindingSource **
My attempt:
Private Sub NumberRows()
For Each oRow As DataGridViewRow In dgvBodyOverview.Rows
oRow.HeaderCell.Value = (oRow.Index + 1).ToString
Next
End Sub
To reproduce your problem, I followed your comment:
I'm calling it from a sub that loads all rows and at the end the call is made.
Doing this, the numbers failed to show whether or not the grid had a DataSource. Instead, I've typically done this as Plutonix suggested above - in DataGridView.CellFormatting.
Private Sub dataGridView1_CellFormatting(sender As Object, e As DataGridViewCellFormattingEventArgs)
Dim header As DataGridViewRowHeaderCell = Me.dataGridView1.Rows(e.RowIndex).HeaderCell
If e.ColumnIndex = 0 Then
header.Value = [String].Format("{0}", e.RowIndex + 1)
End If
End Sub
I check for ColumnIndex = 0 to ensure the header cell value is only set once per row. See this C# answer for additional explanation.

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;