nullreferenceexception in gridview when header is clicked - vb.net

In my DataGridView selectionChange i have this code, so when the row change the texbox also changes. the code below works, i click the row and it displays right, also when i press up/down arrows. My problem is when I click somwhere in the Header of the grid i have this nullreferenceexception error Object reference not set to an instance of an object.. I don't have idea how to handle it, since i down know what it returns.
Private Sub DataGridView1_SelectionChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DataGridView1.SelectionChanged
Dim index As Integer
index = DataGridView1.CurrentCell.RowIndex '<<<<--problem here when I click the header
If (index <= maxrows - 1) Or (index <> Nothing) Then
TextBox2.Text = DataGridView1.Item(1, index).Value()
TextBox3.Text = DataGridView1.Item(2, index).Value()
TextBox4.Text = DataGridView1.Item(3, index).Value()
End If
End Sub

A null reference is raised whenever you get the RowIndex wherein there is no ROW is selected.
Clicking the header calls SORT and this clears the selection.
This will help you get rid of the nullreference exception
If DatagridView1.SelectedRows.Count = 0 Then
Msgbox "Nothing Selected"
Exit Sub 'Trapping
End If
Code:
Private Sub DataGridView1_SelectionChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DataGridView1.SelectionChanged
If DatagridView1.SelectedRows.Count = 0 Then
Msgbox "Nothing Selected"
Exit Sub 'Trapping
End If
Dim index As Integer
With DataGridView
index = .CurrentRow.RowIndex
If (index <= maxrows - 1) Then
TextBox2.Text = .Item(1, index).Value()
TextBox3.Text = .Item(2, index).Value()
TextBox4.Text = .Item(3, index).Value()
End If
End With
End Sub

Related

messagebox appeared second time

In my code, when TextBox3 does not have any value, it must show a notice in a MsgBox to enter a value in TextBox1
But when I run it the MsgBoxnotice appears twice in the screen when it should show only once.
Here is my code:
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
If TextBox3.Text = Nothing Then
TextBox1.Clear()
MsgBox("Enter Number to Textbox1")
Else
Dim digit As Integer = CInt(TextBox3.Text)
If TextBox1.TextLength = digit Then
Dim fields() As String = ListBox1.Text.Split(";")
Dim idx As Integer = ListBox1.FindString(TextBox1.Text)
If idx <> -1 Then
ListBox1.SelectedIndex = idx
ListBox1.SelectedIndex.ToString(fields(0))
ListBox2.Items.Add(Now() + Space(1) + ListBox1.Text.Substring(0, 13))
PrintDocument1.Print()
Else
TextBox1.Clear()
End If
End If
End If
End Sub
The Issue here is that the event handler gets triggered another time because clearing the textbox1 equals the textbox1_changed event handler to go of. You could as well just disable the textbox till the textbox3 is not nothing anymore.
or a quick solution would be aswell
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
If not TextBox1.Text = Nothing AndAlso TextBox3.text = Nothing Then
TextBox1.Clear()
MsgBox("Enter Number to Textbox1")
.............
You are using the wrong event. Textchanged triggers when you clear the textbox as well resulting in two messageboxes.
Use LostFocus instead
Here is the solution,
Public Class Form1
Dim message as boolean = true
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
If TextBox3.Text = Nothing Then
If message Then 'show the message as true
message = False 'set the message false for textbox_changed not appear again
Textbox1.Clear()
message = True 'set the message true for next time textbox change appear again
MsgBox("Enter Number to Textbox3")
End If
Else
Dim digit As Integer = CInt(TextBox3.Text)
If TextBox1.TextLength = digit Then
Dim fields() As String = ListBox1.Text.Split(";")
Dim idx As Integer = ListBox1.FindString(TextBox1.Text)
If idx <> -1 Then
ListBox1.SelectedIndex = idx
ListBox1.SelectedIndex.ToString(fields(0))
ListBox2.Items.Add(Now() + Space(1) + ListBox1.Text.Substring(0, 13))
PrintDocument1.Print()
Else
TextBox1.Clear()
End If
End If
End If
End Sub

Displaying number of rows checked/unchecked on datagridview

I have a datagrid on a form with a checkbox to select all records. Column (0) of my datagrid is a checkbox column, and on the header I put a checkbox to select all records and display the number of records selected. Here is my code:
Private Sub chkSelectRecords_CheckedChanged(sender As Object, e As EventArgs) Handles chkSelectRecords.CheckedChanged
'Procedure runs when the checkSelectRecords is clicked.
'The loop selects all records on the datagrid when checked
'and clears selection when unchecked.
Dim chkRow As Integer = 0
If chkSelectRecords.Checked = True Then
For Each row As DataGridViewRow In grdDeleteRecord.Rows
row.Cells(0).Value = (row.Cells(0).Value IsNot DBNull.Value)
chkRow += 1
lblRowCount.Visible = True
lblRowCount.Text = chkRow.ToString & " Record(s) Selected"
Next
Else
For Each row As DataGridViewRow In grdDeleteRecord.Rows
row.Cells(0).Value = (row.Cells(0).Value Is DBNull.Value)
chkRow += 0
lblRowCount.Text = chkRow.ToString & " Record(s) Selected"
Next
End If
End Sub
I placed another procedure when the user selects one record at a time:
Private Sub grdDeleteRecord_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles grdDeleteRecord.CellContentClick
' Shows how to get count of checked or unchecked checkbox column count along with
' how to get column data back for checked items.
Dim chkRowCount As Integer = 0
grdDeleteRecord.EndEdit()
For Each row As DataGridViewRow In grdDeleteRecord.Rows
If row.Cells(0).Value = True Then
chkRowCount += 1
Else
chkRowCount += 0
lblRowCount.Visible = True
lblRowCount.Text = chkRowCount.ToString & " Record(s) Selected"
End If
Next
End Sub
Both procedures work as needed. The problem is when I select all records my label does not update the number of records that are now selected. I am sure this is happening because they are two separate events, I just don't know how to link the events or write a procedure that accomplishes all three tasks
Here's a function I wrote for you. You must use the CellValueChangedEvent and the CurrentCellDirtyStateChanged events...
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
lblRowCount.Text = SetLabel()
End Sub
Private Function SetLabel() As String
Dim strRows As String = String.Empty
Dim intRows As Integer = 0
For i As Integer = 0 To grdDeleteRecord.Rows.Count - 1
If CBool(grdDeleteRecord(0, i).Value) Then
intRows += 1
End If
Next
If intRows > 0 Then
strRows = intRows.ToString & " Record(s) Selected"
lblRowCount.Visible = True
End If
Return strRows
End Function
Private Sub grdDeleteRecord_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles grdDeleteRecord.CellValueChanged
lblRowCount.Text = SetLabel()
End Sub
Private Sub grdDeleteRecord_CurrentCellDirtyStateChanged(sender As Object, e As EventArgs) Handles grdDeleteRecord.CurrentCellDirtyStateChanged
If grdDeleteRecord.IsCurrentCellDirty Then
grdDeleteRecord.CommitEdit(DataGridViewDataErrorContexts.Commit)
End If
End Sub
When you check or uncheck these checkboxes it will trigger this event and thus update your label. Then you can use this where ever you need it to be used.

Is there any way for Retrieve Record Value from Table Column , Loop and Loop in vb.net

Sorry for my poor English
When the user clicks the Start button, I am trying to display all of the records from the Phone column in the Textbox1 control. I want to see all those records pass into Textbox1 While it is processing the For loop. But it is currently processing very fast so that I only see the last record in Textbox1. What i'm going wrong?
While it is processing the For loop, I change the Start button to a Stop button. So when I click the button and it currently has a Text value equal to "Stop", I want it to skip the For loop and pass the value from TextBox1 to my FirstWin. And then it should change the BtnStart.Text back to "Start"
Here's my code:
Public Class PhoneFortune
Dim CN As OleDbConnection
Dim CM As OleDbCommand
Dim DA As OleDbDataAdapter
Dim DT As New DataTable
Private Sub BtnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnStart.Click
If BtnStart.Text = "Start" Then
CM = New OleDbCommand("SELECT * FROM TblPhoneNumber", CN)
DA = New OleDbDataAdapter(CM)
DA.Fill(DT)
For i = 0 To DT.Rows.Count - 1
TextBox1.Text = DT.Rows(i)("Phone")
Next
BtnStart.Text = "Stop"
End If
If BtnStart.Text = "Stop" Then
If FirstWin.Text = "" Then
FirstWin.Text = TextBox1.Text
BtnStart.Text = "Start"
ElseIf SecondWin.Text = "" Then
SecondWin.Text = TextBox1.Text
BtnStart.Text = "Start"
ElseIf ThirdWin.Text = "" Then
ThirdWin.Text = TextBox1.Text
BtnStart.Text = "Start"
End If
End If
End Sub
Private Sub PhoneFortune_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
CN = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=database\db.accdb;Jet OLEDB:Database Password=12345;")
CN.Open()
End Sub
End Class
I hope we are on the same page but if u want to slow down the process for a bit u use these two lines of code within the FOR loop
System.Threading.Thread.Sleep(1000)
Me.Refresh() Where 1000 is one second(value is represented in milliseconds).
Now what is that FirstWin.Text="" etc used for? Are you trying to start the looping,then change the text to "stop" so that when the user clicks stops it stops at the current record? Go to youtube and look for multithreading videos,not sure how to help u on that one hope the rest helps. If this is useful please acknowledge
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If Button1.Text = "Start" Then
If TextBox1.Text = "" Then
t1 = New Thread(AddressOf Me.PhoneThread)
t1.Start()
Button1.Text = "Stop"
Else
t1.Resume()
Button1.Text = "Stop"
End If
Else 'Click Stop
t1.Suspend()
Button1.Text = "Start"
If FirstWin.Text = "" Then
FirstWin.Text = TextBox1.Text
ElseIf SecondWin.Text = "" Then
SecondWin.Text = TextBox1.Text
ElseIf ThirdWin.Text = "" Then
ThirdWin.Text = TextBox1.Text
End If
End If
End Sub
Sub PhoneThread()
'Dim ThreadsArray As List(Of Threading.Thread) = New List(Of Threading.Thread)
Dim s As Integer
'MsgBox(DT.Rows.Count)
For s = 0 To DT.Rows.Count
If s = DT.Rows.Count Then
s = 0
Else
TextBox1.Text = DT.Rows(s)("Phone")
' ThreadsArray.Add(t1)
Thread.Sleep(19)
'TextBox1.Text = s.ToString()
Me.Refresh()
End If
Next
End Sub
Private Sub BtnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnStart.Click
Me.Close()
End Sub
For something simple like this, System.Threading.Thread.Sleep(100) (to block the thread) followed by Application.DoEvents() (to process any button clicks) seems like it would do the trick.
For something more complicated, this approach will result in re-entrancy and difficult-to-reproduce bugs; in that case, you definitely need asynchronous programming.

Deleting a row in DataGridView on rowLeave

I've got a DataGridView in a vb.net form, not connected to any source. I want to remove a row when the user pass to another row or focus out the DGV. The row should be removed if there's an empty cell in it.
That's my code:
Private Sub dgvSpSettings_RowLeave(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvSpSettings.RowLeave
If e.RowIndex < (dgvSpSettings.Rows.Count - 1) Then 'Esclude l'ultima riga dal controllo sulle righe vuote
If Me.dgvSpSettings.Rows(e.RowIndex).Cells(0).Value Is Nothing OrElse Me.dgvSpSettings.Rows(e.RowIndex).Cells(0).Value.ToString() = "" OrElse Me.dgvSpSettings.Rows(e.RowIndex).Cells(1).Value Is Nothing OrElse Me.dgvSpSettings.Rows(e.RowIndex).Cells(1).Value.ToString() = "" Then
Me.dgvSpSettings.Rows.RemoveAt(e.RowIndex)
End If
End If
End Sub
This doesn't work because I can't perform the method Me.dgvSpSettings.Rows.RemoveAt(e.RowIndex) in this event. I tried to store the row in a private var and then delete it in other events (like click), but the result is not what I expected.
Any suggestions?
This is probably not the best possible solution but atleast I've come up with something that might work for you. Basically you set the row to read only instead of deleting it. And since paint is called when you leave the row you can put the deletion code in paint instead.
Private Sub DataGridView1_RowLeave(sender As System.Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.RowLeave
DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
If e.RowIndex < (DataGridView1.Rows.Count - 1) Then
If Me.DataGridView1.Rows(e.RowIndex).Cells(0).Value Is Nothing OrElse _
Me.DataGridView1.Rows(e.RowIndex).Cells(0).Value.ToString() = "" OrElse _
Me.DataGridView1.Rows(e.RowIndex).Cells(1).Value Is Nothing OrElse _
Me.DataGridView1.Rows(e.RowIndex).Cells(1).Value.ToString() = "" Then
Me.DataGridView1.Rows(e.RowIndex).ReadOnly = True
End If
End If
End Sub
Private Sub DataGridView1_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles DataGridView1.Paint
Dim i As Integer = 0
While i <> DataGridView1.Rows.Count - 1
If DataGridView1.Rows(i).ReadOnly Then
DataGridView1.Rows.RemoveAt(i)
If i = DataGridView1.Rows.Count - 1 Then
Exit While
End If
Else
i += 1
End If
End While
End Sub
You can't delete the row in the RowLeave event handling because it is "busy".
A solution for this type of cases that I sometimes apply is to invoke the application.Idle event (I do not really like it, because it feels clumsy, but it works well):
Private Sub dgvSpSettings_RowLeave(sender As Object, e As DataGridViewCellEventArgs) Handles dgvSpSettings.RowLeave
Dim row As DataGridViewRow = dgvSpSettings.Rows(e.RowIndex)
If Me.dgvSpSettings.Rows(e.RowIndex).Cells(0).Value Is Nothing OrElse
e.dgvSpSettings.Rows(e.RowIndex).Cells(0).Value.ToString() = "" OrElse
Me.dgvSpSettings.Rows(e.RowIndex).Cells(1).Value Is Nothing OrElse
Me.dgvSpSettings.Rows(e.RowIndex).Cells(1).Value.ToString() = "" Then
Me._rowToDelete = row
AddHandler Application.Idle, AddressOf AppIdle
End If
End Sub
Private _rowToDelete As DataGridViewRow
Private Sub AppIdle(sender As Object, e As EventArgs)
If Me._rowToDelete IsNot Nothing Then
dgvSpSettings.Rows.Remove(Me._rowToDelete)
Me._rowToDelete = Nothing
End If
RemoveHandler Application.Idle, AddressOf AppIdle
End Sub
That's my final solution. It works for me and I hope it's conceptually correct. I used delegates and Leave + LostFocus events.
'**********
'* Controllo righe da eliminare
'**********
Private Sub dgvSpSettings_RowLeave(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvSpSettings.RowLeave
Me.dgvSpSettings.CommitEdit(0)
Dim row As DataGridViewRow = Me.dgvSpSettings.Rows(e.RowIndex)
For Each cell In row.Cells
cell.Style.BackColor = Color.White
Next
If Not row.IsNewRow() Then 'Esclude l'ultima riga dal controllo sulle righe vuote
If String.IsNullOrEmpty(row.Cells(0).Value) OrElse String.IsNullOrEmpty(row.Cells(1).Value) Then
_rowBlank = row
End If
End If
End Sub
Private Delegate Sub setCurrentCellDelegate()
Private Sub setCurrentCell()
For Each cell In _rowBlank.Cells
cell.Style.BackColor = Color.LightSalmon
Next
Me.dgvSpSettings.CurrentCell = _rowBlank.Cells(0)
Me.dgvSpSettings.BeginEdit(True)
_rowBlank = Nothing
End Sub
Private Delegate Sub removeRowDelegate()
Private Sub removeRow()
Me.dgvSpSettings.Rows.Remove(_rowBlank)
_rowBlank = Nothing
_rowBlankDeleting = False
End Sub
'**********
'* Controllo righe da eliminare
'**********
Private Sub dgvSpSettings_Leave(sender As Object, e As System.EventArgs) Handles dgvSpSettings.Leave
If _rowBlank IsNot Nothing AndAlso _rowBlankDeleting = False Then
If MsgBox("Alcuni campi della riga non sono stati valorizzati. Eliminare la riga?", vbYesNo + vbInformation, "Eliminare") = MsgBoxResult.Yes Then
_rowBlankDeleting = True
Me.dgvSpSettings.BeginInvoke(New removeRowDelegate(AddressOf removeRow))
Else
Me.dgvSpSettings.BeginInvoke(New setCurrentCellDelegate(AddressOf setCurrentCell))
End If
End If
End Sub
'**********
'* Controllo righe da eliminare
'**********
Private Sub dgvSpSettings_LostFocus(sender As Object, e As System.EventArgs) Handles dgvSpSettings.LostFocus
If _rowBlank IsNot Nothing AndAlso _rowBlank IsNot Me.dgvSpSettings.CurrentRow AndAlso _rowBlankDeleting = False Then
If MsgBox("Alcuni campi della riga non sono stati valorizzati. Eliminare la riga?", vbYesNo + vbInformation, "Eliminare") = MsgBoxResult.Yes Then
_rowBlankDeleting = True
Me.dgvSpSettings.BeginInvoke(New removeRowDelegate(AddressOf removeRow))
Else
Me.dgvSpSettings.BeginInvoke(New setCurrentCellDelegate(AddressOf setCurrentCell))
End If
End If
End Sub
Actually the problem is that you can't delete from the bottom up (1, 2. 3, etc) you have to go from top to bottom (3, 2, 1) like this:
For j = DataGrid1.Rows.Count - 2 To 0 Step -1
DataGrid1.Rows.RemoveAt(j)
Next
The problem is that VB considers the first row to be the row that doesn't contain any data (the empty one you can enter information into.) This one worked for me.

VB.NET ListView Questions

I have Questions?
If I enter a data in a textbox,
I want my listview to select the same data entered in the textbox,
example,
I have a StudentNumber column in my listview and it has data on it(ex. 123456)
I will enter 123456 in the textbox.
The ListView must select 123456 ?
Please Help
THANK YOU,
I think this will do what you want. It will search the first column of the ListView for the text in the TextBox.
Setup the listview:
With ListView1
.MultiSelect = False 'Ensure only one item selected at a time
.HideSelection = False 'Shows the selection when the textbox changes
'Add some items for testing
.Items.Add("1234")
.Items.Add("1122")
.Items.Add("1133")
End With
Then in the textbox TextChanged changed event:
Private Sub TextBox1_TextChanged(sender As System.Object, e As System.EventArgs) Handles TextBox1.TextChanged
ListView1.SelectedItems.Clear()
Dim foundItem As ListViewItem = ListView1.FindItemWithText(TextBox1.Text, False, 0, False)
If (foundItem IsNot Nothing) Then foundItem.Selected = True
End Sub
Alternatively if you want to specify which column of your ListView to search for the text then this function should do the trick:
Private Sub SelectListViewItem(ByRef listviewSource As ListView, ByVal textToFind As String, ByVal column As Integer)
Dim foundItem As ListViewItem = Nothing
Dim startIndex As Integer = 0
listviewSource.SelectedItems.Clear()
Do Until Not foundItem Is Nothing AndAlso foundItem.SubItems(column).Text = TextBox2.Text
If foundItem Is Nothing Then startIndex = 0 Else startIndex = foundItem.Index + 1
If startIndex > listviewSource.Items.Count - 1 Then Exit Sub 'We have reached end of the listview
foundItem = listviewSource.FindItemWithText(textToFind, True, startIndex)
If foundItem Is Nothing Then Exit Sub
Loop
If (foundItem IsNot Nothing) Then foundItem.Selected = True
End Sub
Usage:
Private Sub TextBox2_TextChanged(sender As System.Object, e As System.EventArgs) Handles TextBox2.TextChanged
SelectListViewItem(ListView1, TextBox2.Text, 1)
End Sub
Warning - In both cases, this may cause your application to perform poorly if you have a lot of items in your listview, in that case you could consider moving the code into a background worker