How to use function to prevent duplicated record for datagridview - vb.net

I use function to prevent the same record goes into my datagridview but it doesnt work , when i separate the code out then its worked
i tried to seperate the for loop part out then the code work , but i wan to use function to do it so the code look more neater
Private Sub PicFavNote10_Click(sender As Object, e As EventArgs) Handles picFavNote10.Click
If validationDataGrid(lblNameNote10.Text) <> True Then
'if item didn added to the favorite data table yet
'add to favorite table
addTofavorite(lblUserLogin.Text, lblNameNote10.Text, lblDecpNote10.Text, txtPicNote10.Text, "SmartPhone", lblPriceNote10.Text)
End If
lblPriceNote10.Text = FormatCurrency(lblPriceNote10.Text)
End Sub
Private Function validationDataGrid(ByRef data As String) As Boolean
'validation on data grid view
For Each itm As DataGridViewRow In DGTFavTable.Rows 'loop though every item in datagrid
If itm.Cells(0).Value = data Then 'check wherter the text already exist
MsgBox(data & " Already added to your favorite cart")
Return True
Else
Return False
End If
Next
End Function
I expected the MsgBox(data & " Already added to your favorite cart") will excecute but instead the validationDataGrid function return false value even the item is already added to favorite datagridview

Before you loop all rows you need to call this sub as is an efficient workaround to validate new data on DataGridView:
Private Sub ForceGridValidation()
'Get the current cell
Dim currentCell As DataGridViewCell = DGTFavTable.CurrentCell
If currentCell IsNot Nothing Then
Dim colIndex As Integer = currentCell.ColumnIndex
If colIndex < DGTFavTable.Columns.Count - 1 Then
DGTFavTable.CurrentCell = DGTFavTable.Item(colIndex + 1, currentCell.RowIndex)
ElseIf colIndex > 1 Then
DGTFavTable.CurrentCell = DGTFavTable.Item(colIndex - 1, currentCell.RowIndex)
End If
'Set the original cell
DGTFavTable.CurrentCell = currentCell
End If
End Sub

Related

DataGridView live search data

I am trying to add a search function to a DataGridView in vb.net using this code
For i As Integer = 0 To ContactsList.RowCount - 1
For j As Integer = 0 To ContactsList.ColumnCount - 1
If ContactsList.Rows(i).Cells(j).Value.ToString.ToLower.Trim = ContactsListSearch.Text.ToLower.Trim Then
MsgBox("Item found " + i.ToString)
ContactsList.Rows(i).Visible = True
Else
ContactsList.Rows(i).Visible = False
End If
Next
Next
I'm seeing the MsgBox show when the value matches, but the rows are not showing, it just hides all rows
Another possible option is to load data into a DataTable, create a BindingSource, set the BindingSource DataSource property to the DataTable. Set the DataGridView DataSource property to the BindingSource.
The following example works against a column in the DataTable. If the user clears the TextBox the filter is removed while if there is text filter with trim.
Private Sub SearchButton_Click(sender As Object, e As EventArgs) _
Handles SearchButton.Click
If String.IsNullOrWhiteSpace(SearchTextBox.Text) Then
bindingSource.Filter = ""
Else
Dim currentRowCount = bindingSource.Count
bindingSource.Filter = $"TRIM(LastName) = '{SearchTextBox.Text}'"
MessageBox.Show($"Before: {currentRowCount} Now: {bindingSource.Count}")
End If
End Sub
Edit If the column name might be variable consider loading a ComboBox with column names then adjust code as follows.
bindingSource.Filter = $"TRIM({FilterComboBox.Text}) = '{SearchTextBox.Text}'"
In most cases working against a data source is better than working against cells values as per the above recommendation.
I added 2 Exits in the IF statement when the value matches as it's searching each column as well, so it was causing them to be hidden as it loops columns too
For i As Integer = 0 To ContactsList.RowCount - 1
For j As Integer = 0 To ContactsList.ColumnCount - 1
If ContactsList.Rows(i).Cells(j).Value.ToString.ToLower.Trim = ContactsListSearch.Text.ToLower.Trim Then
MsgBox("Item found " + i.ToString)
ContactsList.Rows(i).Visible = True
Else
ContactsList.Rows(i).Visible = False
End If
Next
Next

Remove specific row of TableLayoutPanel using dynamically created button of each row

So I am making a function that will populate the TableLayoutPanel from FileDialog Result then make a delete button for each row using a loop. Here's the code
Private PathtoFile1 As New List(Of String) 'this will contain all the selected file in the dialogwindow
Private rowLineDrawing As Integer = 0
Private selectedfilecountLineDrawing As Integer
Public Function AttachFileLineDrawing(TLP As TableLayoutPanel)
Dim dr = OpenFileDialog1.ShowDialog
If (dr = System.Windows.Forms.DialogResult.OK) Then
selectedfilecountLineDrawing = OpenFileDialog1.FileNames.Count
For Each FileName In OpenFileDialog1.FileNames
Try
Console.WriteLine(FileName.ToString)
PathtoFile1.Add(FileName.ToString)
Catch SecEx As Security.SecurityException
MessageBox.Show("Security error. Please contact your administrator for details.\n\n" &
"Error message: " & SecEx.Message & "\n\n" &
"Details (send to Support):\n\n" & SecEx.StackTrace)
Catch ex As Exception
'Could Not Load the image - probably permissions-related.
MessageBox.Show(("Cannot display the image: " & FileName.Substring(FileName.LastIndexOf("\"c)) &
". You may not have permission to read the file, or " + "it may be corrupt." _
& ControlChars.Lf & ControlChars.Lf & "Reported error: " & ex.Message))
End Try
Next
'MAKE SOMETHING HERE TO DISPLAY THE SELECTED ITEMS IN THE TABLELAYOUTPANEL OF THE SUBMIT PROGRESS
TLP.Controls.Clear()
TLP.RowCount = 0
rowLineDrawing = 0
For Each Path In PathtoFile1
Dim filepath As New Label
filepath.Text = Path
filepath.Width = Val(360)
'this button is for previewing the file
Dim btnPreview As New Button
AddHandler btnPreview.Click,
Sub(s As Object, e As EventArgs)
Dim btn = CType(s, Button)
MsgBox("This is Preview")
End Sub
'This button is for removing rows in the tablelayoutpanel
Dim btnRmv As New Button
Dim StringToIndex As String = Path 'THIS CATCHES EVERY PATH IN THE LOOP AND STORE IT TO THE VARIABLE WHICH THEN BE USED AS A COMPARABLE PARAMETER FOR THE INDEX SEARCH
Dim index = PathtoFile1.IndexOf(Path)
AddHandler btnRmv.Click,
Sub(s As Object, e As EventArgs)
Dim btn = CType(s, Button)
MsgBox(index)
PathtoFile1.RemoveAt(index) 'THIS LINE OF CODE REMOVE THE SPECIFIC ITEM IN THE LIST USING THE BTNRMV CLICK
'MAKE SOMETHING HERE TO REMOVE THE ROW IN THE TABLELAYOUTAPANEL
End Sub
TLP.SuspendLayout()
TLP.RowStyles.Add(New RowStyle(SizeType.Absolute, 20))
TLP.Controls.Add(filepath, 0, rowLineDrawing)
TLP.Controls.Add(btnPreview, 1, rowLineDrawing)
TLP.Controls.Add(btnRmv, 2, rowLineDrawing)
TLP.ResumeLayout()
rowLineDrawing -= -1
Next
End If
End Function
So I am trying to remove the row in the TableLayoutPanel together with the dynamic control. My approach is removing the selected item in the list and I achieved it properly but can't remove the row in the TableLayoutPanel. Any help is much appreciated!
EDIT
I have tried to use the provided module above but got this error
And got this error
Here is an extension method that will enable you to remove any row from a TableLayoutPanel by index:
Imports System.Runtime.CompilerServices
Public Module TableLayoutPanelExtensions
<Extension>
Public Sub RemoveRowAt(source As TableLayoutPanel, index As Integer)
If index >= source.RowCount Then
Throw New ArgumentOutOfRangeException(NameOf(index),
index,
"The row index must be less than the number of rows in the TableLayoutPanel control.")
End If
'Remove the controls in the specified row.
For columnIndex = 0 To source.ColumnCount - 1
Dim child = source.GetControlFromPosition(columnIndex, index)
If child IsNot Nothing Then
child.Dispose()
End If
Next
'Move controls below the specified row up.
For rowIndex = index + 1 To source.RowCount - 1
For columnIndex = 0 To source.ColumnCount - 1
Dim child = source.GetControlFromPosition(columnIndex, rowIndex)
If child IsNot Nothing Then
source.SetCellPosition(child, New TableLayoutPanelCellPosition(columnIndex, rowIndex - 1))
End If
Next
Next
'Remove the last row.
source.RowCount -= 1
End Sub
End Module
I tested that on 3 column by 4 row TableLayoutPanel containing a Label in each cell executing the following code twice:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TableLayoutPanel1.RemoveRowAt(1)
End Sub
The result was as expected, i.e. removing the second-from-top row each time. You may need to fiddle a bit more depending on what you want to happen row heights. I had the row heights set to equal percentages so the remaining rows grew proportionally to fill the space. If you want something different, you can add code accordingly. Note that you could create an almost identical method for removing columns.

How to compare DataGridView cell data to DataSet cell data

In a VB.NET WinForms project I'm working on in VS2013 I am detecting when the user changes something in a cell on the CellValueChanged event. When a row in the DataGridView is found that is different from the DataSet I highlight the row in pink.
In my code though, I only know how to iterate through all of the rows, rather than just compare the row that fired the CellValueChanged event to the DataSet.
Here's my current code:
Private Sub dgvEmployees_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles dgvEmployees.CellValueChanged
' Pass the row and cell indexes to the method so we can change the color of the edited row
CompareDgvToDataSource(e.RowIndex, e.ColumnIndex)
End Sub
Private Sub CompareDgvToDataSource(ByVal rowIndex As Integer, ByVal columnIndex As Integer)
' Force ending Edit mode so the last edited value is committed
EmployeesBindingSource.EndEdit()
Dim dsChanged As DataSet = EmployeesDataSet.GetChanges()
If Not dsChanged Is Nothing Then
For Each dt As DataTable In dsChanged.Tables
For Each row As DataRow In dt.Rows
For i As Integer = 0 To dt.Columns.Count - 1
Dim currentColor As System.Drawing.Color = dgvEmployees.AlternatingRowsDefaultCellStyle.BackColor
If Not row(i, DataRowVersion.Current).Equals(row(i, DataRowVersion.Original)) Then
Console.WriteLine("Row index: " & dt.Rows.IndexOf(row))
' This works
dgvEmployees.Rows(rowIndex).DefaultCellStyle.BackColor = Color.LightPink
Else
' Need to change the BackColor back to what it should be based on its original alternating row color
End If
Next
Next
Next
End If
End Sub
As you can see, I'm passing the row and column index of the changed cell, so how can I take that and compare it to the specific row and/or cell in the unchanged DataSet?
UPDATE
Nocturnal reminded me that I need to allow for sorting of the DGV, so using row indexes won't work. He offered this as a solution (changed slightly to work with my objects):
If Not dsChanged Is Nothing Then
For Each dtrow As DataRow In dsChanged.Tables("employees").Rows
If DirectCast(dtrow, EmployeesDataSet.employeesRow).employeeID.ToString = dgvEmployees.Rows(rowIndex).Cells("employeeID").Value.ToString Then
For i As Integer = 0 To dsChanged.Tables("employees").Columns.Count - 1
If Not dtrow(i, DataRowVersion.Current).Equals(dtrow(i, DataRowVersion.Original)) Then
Console.WriteLine("Employees ID: " & DirectCast(dtrow, EmployeesDataSet.employeesRow).employeeID)
dgvEmployees.Rows(rowIndex).Cells(columnIndex).Style.BackColor = Color.LightPink
Else
' Need to change the BackColor back to what it should be based on its original alternating row color
End If
Next
End If
Next
End If
However, I'm getting an error on the If DirectCast... line saying "Column named "employeeID" cannot be found." I'm not sure if the error is on the DataSet or on the DGV, but there is an employeeID column in the database and DataSet. There is an employeeID as a bound column for the DataGridView, but it is set to Visible = False. That's the only thing I can think of that could possibly cause that error, but if it's a bound column, I would think it could be compared against as in this case.
FINAL WORKING VERSION
Private Sub dgvEmployees_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles dgvEmployees.CellValueChanged
' Pass the row and cell indexes to the method so we can change the color of the edited row
CompareDgvToDataSource("employees", e.RowIndex, e.ColumnIndex)
End Sub
Private Sub CompareDgvToDataSource(ByVal dataSetName As String, ByVal rowIndex As Integer, ByVal columnIndex As Integer)
' Takes a dataset and the row and column indexes, checks if the row is different from the DataSet and colors the row appropriately
EmployeesBindingSource.EndEdit()
Dim dsChanges As DataSet = EmployeesDataSet.GetChanges()
If Not dsChanges Is Nothing Then
For Each dtrow As DataRow In dsChanges.Tables("employees").Rows
If DirectCast(dtrow, EmployeesDataSet.employeesRow).employeeID.ToString = dgvEmployees.Rows(rowIndex).Cells("employeeID").Value.ToString Then
For i As Integer = 0 To dsChanges.Tables("employees").Columns.Count - 1
If dtrow.RowState.ToString = DataRowState.Added.ToString Then
' TODO: Color entire new row
ElseIf dsChanges.Tables(dataSetName).Rows(0).HasVersion(DataRowVersion.Original) Then
If Not dtrow(i, DataRowVersion.Current).Equals(dtrow(i, DataRowVersion.Original)) Then
Console.WriteLine("Employees ID: " & DirectCast(dtrow, EmployeesDataSet.employeesRow).employeeID)
dgvEmployees.Rows(rowIndex).Cells(columnIndex).Style.BackColor = Color.LightPink
Else
' TODO: Need to change the BackColor back to what it should be based on its original alternating row color
End If
End If
Next
End If
Next
End If
End Sub
My project has four DGVs in it, so this will eventually be expanded to allow for all four DGVs to be checked for changes.
have a look at this approach it is simlar but only iterating the specific Table
Private Sub dgvEmployees_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles dgvEmployees.CellValueChanged
' Pass the row and cell indexes to the method so we can change the color of the edited row
CompareDgvToDataSource(e.RowIndex, e.ColumnIndex, sender.DataSource.datamember.ToString)
End Sub
and comparing the ID of the given Table
Private Sub CompareDgvToDataSource(ByVal rowIndex As Integer, ByVal columnIndex As Integer, tablename As String)
EmployeesBindingSource.EndEdit()
Dim dsChanged As DataSet = EmployeesDataSet.GetChanges()
If Not dsChanged Is Nothing Then
For Each dtrow As DataRow In dsChanged.Tables(tablename).Rows
If DirectCast(dtrow, EmployeesDataSet.EmployeeRow).EmployeeID = dgvEmployees.Rows(rowIndex).Cells("EmployeeID").Value Then
Dim currentColor As System.Drawing.Color = dgvEmployees.AlternatingRowsDefaultCellStyle.BackColor
For i As Integer = 0 To dsChanged.Tables(tablename).Columns.Count - 1
If Not dtrow(i, DataRowVersion.Current).Equals(dtrow(i, DataRowVersion.Original)) Then
Console.WriteLine("Employees ID: " & DirectCast(dtrow, EmployeesDataSet.EmployeeRow).EmployeeID)
' This works
dgvEmployees.Rows(rowIndex).Cells(columnIndex).Style.BackColor = Color.LightPink
Else
' Need to change the BackColor back to what it should be based on its original alternating row color
End If
Next
End If
Next
End If
End Sub
and i am only changing the backcolor of the cell that was changed not the entire row....but depends how you would use that information anyways
EDIT:
with
Console.WriteLine(EmployeesDataSet.Employee(rowIndex)(columnIndex, DataRowVersion.Original).ToString())
Console.WriteLine(EmployeesDataSet.Employee(rowIndex)(columnIndex, DataRowVersion.Current).ToString())
you can see Current and Original Values
123456

How to search in listview

I am trying to create a Loop that will read through the information on my ListView through the SubItem to find the text that matches the text in my Textbox whenever I hit the search button and Focuses the listbox onto the matched text. Below is what I have but it keeps telling me that the value of string cannot be converted. I am also pretty sure that my numbers wont loop correctly but I am not really sure how to cause them to loop endlessly till end of statement.
Dim T As String
T = Lines.Text
For r As Integer = 0 to -1
For C As Integer = 0 to -1
If List.Items(r).SubItems(C).Text = Lines.Text Then
List.FocusedItem = T
End If
Next
Next
End Sub
I don't understand your code, but I do understand the question. Below is example code to search all rows and columns of a listview. Search is case insensitive and supports a "find next match" scenario. If a match or partial match is found in any column the row is selected. TextBox1 gets the text to find. FindBtn starts a new search.
Private SrchParameter As String = ""
Private NxtStrtRow As Integer = 0
Private Sub FindBtn_Click(sender As Object, e As EventArgs) Handles FindBtn.Click
If Not String.IsNullOrWhiteSpace(TextBox1.Text) Then
SrchParameter = TextBox1.Text
NxtStrtRow = 0
SearchListView()
End If
End Sub
Private Sub ListView1_KeyDown(sender As Object, e As KeyEventArgs) Handles ListView1.KeyDown
If e.KeyCode = Keys.F3 Then
SearchListView()
End If
End Sub
Private Sub SearchListView()
' selects the row containing data matching the text parameter
' sets NxtStrtRow (a form level variable) value for a "find next match" scenario (press F3 key)
If ListView1.Items.Count > 0 Then
If SrchParameter <> "" Then
Dim thisRow As Integer = -1
For x As Integer = NxtStrtRow To ListView1.Items.Count - 1 ' each row
For y As Integer = 0 To ListView1.Columns.Count - 1 ' each column
If InStr(1, ListView1.Items(x).SubItems(y).Text.ToLower, SrchParameter.ToLower) > 0 Then
thisRow = x
NxtStrtRow = x + 1
Exit For
End If
Next
If thisRow > -1 Then Exit For
Next
If thisRow = -1 Then
MsgBox("Not found.")
NxtStrtRow = 0
TextBox1.SelectAll()
TextBox1.Select()
Else
' select the row, ensure its visible and set focus into the listview
ListView1.Items(thisRow).Selected = True
ListView1.Items(thisRow).EnsureVisible()
ListView1.Select()
End If
End If
End If
End Sub
Instead of looping like that through the ListView, try using a For Each instead:
searchstring as String = "test1b"
ListView1.SelectedIndices.Clear()
For Each lvi As ListViewItem In ListView1.Items
For Each lvisub As ListViewItem.ListViewSubItem In lvi.SubItems
If lvisub.Text = searchstring Then
ListView1.SelectedIndices.Add(lvi.Index)
Exit For
End If
Next
Next
ListView1.Focus()
This will select every item which has a text match in a subitem.
Don't put this code in a form load handler, it won't give the focus to the listview and the selected items won't show. Use a Button click handler instead.
This is the easiest way to search in listview and combobox controls in vb net
dim i as integer = cb_name.findstring(tb_name.text) 'findstring will return index
if i = -1 then
msgbox("Not found")
else
msgbox("Item found")
end if

System.NullReferenceException on a ForEach of a datagrid

So all is in the question, I have a datagrid view who's parcoured by a foreach in his rows collection like so dataGridView1.Rows and I get and error of null type in the second if of the for each
Sub DataColumnFirstDouble(ByRef dGridView As DataGridView, ByVal iCol As Integer)
Dim bFirstRow As Boolean = False
Dim sTemp As String = ""
For Each RW As DataGridViewRow In dGridView.Rows
If (bFirstRow) Then
If (RW.Cells(iCol).Value.ToString() = sTemp) Then
RW.Cells(iCol).Selected = True
dGridView.CurrentCell.Style.BackColor = Color.LightGreen
dGridView.CurrentCell.Style.ForeColor = Color.White
End If
End If
sTemp = RW.Cells(iCol).Value.ToString()
bFirstRow = True
Next
End Sub
By the way the Datagrid is populated with 1 entry going
LongString, Number, Number
Hello , 8 , 8
The bug occur when I click on a new row also the function is called on the event of row leave
Need some help
By the way what I try to do is to check when the user enter the name in the longstring space who's a primary unique key in a database but It seems I can't find anythings to handle it by vb so I try to parse it every times he leave the rows to check if there's any double
It isn't clear where the error is, you should debug to figure out which variable exactly is null. So I'll assume it's RW.Cells(iCol).Value.
If there's no value in the cell, it might be null. This mean ToString won't work.
If (bFirstRow) Then
If RW.Cells(iCol).Value IsNot Nothing AndAlso RW.Cells(iCol).Value.ToString() = sTemp Then
RW.Cells(iCol).Selected = True
dGridView.CurrentCell.Style.BackColor = Color.LightGreen
dGridView.CurrentCell.Style.ForeColor = Color.White
End If
End If
You could even check if RW.Cells(iCol) exists, maybe it's trying to fetch the data in a cell that doesn't exists in the row.