Checking existing database record items against listbox items - vb.net

I have a datatable that I am adding records to in my windows forms application. this datatable only has 2 columns and the first column is the primary key and is an integer. The second column contains names and I need to automatically add a list of names from a listbox to the table. Most of these names will already have their own record in the table but there will be different names in the listbox each time. I need to check the existing record items against the listbox items to make sure no duplicates get added, but if there is a name in the listbox that does not exist in the datatable, add a new record for that name.
What I have tried so far is this:
Private m_cn As New SqlConnection()
Private m_DA As SqlDataAdapter
Private m_CB As SqlCommandBuilder
Private m_DataTable As New DataTable
Private m_IntRowPosition As Integer = 0
Private Sub btnInsertIntoDatabase_Click(sender As Object, e As EventArgs) Handles btnInsertIntoDatabase.Click
Dim drReadRow As DataRow = m_DataTable.NewRow()
Dim dcReadCol As DataColumn = m_DataTable.Columns.Item(1)
Dim intLoopCounter As Integer = 0
Dim unique As Boolean = True
If m_DataTable.Rows.Count = 0 Then
For m_IntRowPosition = 0 To (lstScannedNames.Items.Count() - 1)
Dim drNewRow As DataRow = m_DataTable.NewRow()
drNewRow("emp_id") = m_IntRowPosition
drNewRow("emp_name") = RTrim(lstScannedNames.Items.Item(RTrim(m_IntRowPosition)))
m_DataTable.Rows.Add(drNewRow)
Next m_IntRowPosition
GoTo SomeWhereElse
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
ElseIf m_DataTable.Rows.Count > 0 Then
For m_IntRowPosition = 0 To m_DataTable.Rows.Count
For intLoopCounter = 0 To lstScannedNames.Items.Count - 1
If RTrim(m_DataTable.Rows(m_IntRowPosition).Item(1)) = lstScannedNames.Items.Item(intLoopCounter) Then
unique = False
ElseIf RTrim(m_DataTable.Rows(m_IntRowPosition).Item(1)) <> lstScannedNames.Items.Item(intLoopCounter) Then
unique = True
lstScannedNames.SelectedIndex = intLoopCounter
intLoopCounter = lstScannedNames.Items.Count - 1
End If
Next intLoopCounter
If (unique) = True Then
Dim drNewRow As DataRow = m_DataTable.NewRow()
drNewRow("emp_id") = m_DataTable.Rows.Count()
drNewRow("emp_name") = lstScannedNames.Items.Item(lstScannedNames.SelectedIndex)
m_DataTable.Rows.Add(drNewRow)
Else
unique = True
End If
Next m_IntRowPosition
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
End If
SomeWhereElse:
m_DA.Update(m_DataTable)
MessageBox.Show("Operation Completed")
End Sub
The area of focus is the ElseIf statement. When I run this code and there are already records in the database, it adds the first name that is in the list and not in the datatable, to the datatable. It then adds the first name from the list to a new record, for each item in the list, which is about 20 times but it depends on the list length. I've been trying different things and I know I'm close but I've been stuck for a while.

Reverse your logic. Loop over the items in the listbox and check if they are present in the datatable
....
For intLoopCounter = 0 To lstScannedNames.Items.Count - 1
Dim name = lstScannedNames.Items.Item(intLoopCounter)
Dim rowExist = m_DataTable.Select("emp_name = '" & name & "'")
if rowExist Is Nothing OrElse rowExist.Length = 0 Then
Dim drNewRow As DataRow = m_DataTable.NewRow()
drNewRow("emp_id") = m_DataTable.Rows.Count()
drNewRow("emp_name") = name
m_DataTable.Rows.Add(drNewRow)
End If
Next m_IntRowPosition
...
Using the DataTable.Select method avoids to write an explicit loop to find the duplicate. And you can directly add the row when you are certain that there is no duplicate

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

How to freeze merged columns in data grid view when scrolling vertically?

I have a data grid view where I need the columns to be frozen or fixed when scrolling vertically.
I have a data grid view control in vb.net windows application which displays the data in a parent-child hierarchy(as shown below). The first column displays the parent data and the second column displays all its child data. The child data in the second column can be as much as 100 rows or even more. So when scrolling down through the grid, the value in the first column does not remain there as it is while the values in the second column(i.e. the child data) scrolls down. So if the user wants to check to which parent, the current child info belongs to, then again he will have to scroll up to the starting of the column to find the name of the parent. I want the values in the first column to be displayed or frozen till it reaches the end of the list of its child values in the grid or at least till the next row where the next parent data starts. I have suggested the client to go with a tree view but they are not agreeing and need it in a data grid view itself. Is there anyway to achieve this in a data grid view?
Thanks in advance.
You can't freeze a row (in runtime, on dgv scrolling) with index greater than zero because all those before are frozen and at that point you can't scroll your datagridview.
If I understood correctly what you want I wrote this class quickly (probably should be optimized). Usage is simple.
1 - First create your own datagridview.
2 - then add your columns and rows (IMPORTANT: Put a “X” in the Tag in each row is a Parent or is considered as title for other rows as you seen in TestPopulate method) .
3 - Call the class I made by passing the datagridview (you created first) as a parameter. At this point this control takes its size, placement and REPLACE YOUR DATAGRIDVIEW .
Private Class CustomDgv
Inherits Panel
Dim WithEvents TopDgv As DataGridView = New DataGridView
Dim WithEvents DownDgv As DataGridView = New DataGridView
Dim Cols As Integer
' This variable is in case you have more rows as "headrow"
' In TestPopulate you can see how to get those
Dim listOfOwnerRows As List(Of Integer) = New List(Of Integer)
Dim currentTopRow As Integer = -1
Protected Overloads Property Height As Integer
Get
Return MyBase.Height
End Get
Set(value As Integer)
MyBase.Height = value
TopDgv.Height = TopDgv.RowTemplate.Height - 1
DownDgv.Height = value - TopDgv.Height - 1
End Set
End Property
Protected Overloads Property Width As Integer
Get
Return MyBase.Width
End Get
Set(value As Integer)
MyBase.Width = value
TopDgv.Width = value - 1
DownDgv.Width = value - 1
End Set
End Property
Sub New(dgvOriginal As DataGridView)
DownDgv = dgvOriginal
Dim parentCtrl As Control = dgvOriginal.Parent
parentCtrl.Controls.Remove(dgvOriginal)
parentCtrl.Controls.Add(Me)
Me.Location = DownDgv.Location
Me.Size = DownDgv.Size
Me.BorderStyle = DownDgv.BorderStyle
TopDgv.Width = Width - 2 - SystemInformation.VerticalScrollBarWidth
TopDgv.Height = TopDgv.RowTemplate.Height
TopDgv.ScrollBars = ScrollBars.None
TopDgv.ColumnHeadersVisible = False
TopDgv.BorderStyle = BorderStyle.None
DownDgv.ColumnHeadersVisible = False
DownDgv.BorderStyle = BorderStyle.None
TopDgv.Left = 0
DownDgv.Left = 0
DownDgv.Width = Width - 2
DownDgv.Height = Height - 2
For Each Col As DataGridViewColumn In DownDgv.Columns
Dim cIndex As Integer = TopDgv.Columns.Add(Col.Clone)
If Col.Frozen Then
TopDgv.Columns(cIndex).Frozen = True
End If
Cols += 1
Next
DownDgv.Top = 0
Me.Controls.Add(TopDgv)
Me.Controls.Add(DownDgv)
If DownDgv.Rows.Count > 0 Then
listOfOwnerRows = (From R As DataGridViewRow In DownDgv.Rows
Where R.Tag = "X"
Select R.Index).ToList
If listOfOwnerRows.Count > 0 Then
SetFrosenRow(listOfOwnerRows(0))
End If
End If
End Sub
Protected Sub SetFrosenRow(index As Integer)
If DownDgv.Rows.Count > index Then
TopDgv.Rows.Clear()
TopDgv.Rows.Add()
Dim currentRIndex As Integer = DownDgv.FirstDisplayedScrollingRowIndex
'If you want onlly the base row
For i As Integer = 0 To Cols - 1
TopDgv.Rows(0).Cells(i).Value = DownDgv.Rows(index).Cells(i).Value
Next
'Or else get the diplayed on top row
TopDgv.Rows(0).DefaultCellStyle = New DataGridViewCellStyle With {
.BackColor = Color.Bisque
}
currentTopRow = index
End If
End Sub
Protected Sub SetChildValuesInTopRow(index As Integer)
For i As Integer = 1 To Cols - 1
TopDgv.Rows(0).Cells(i).Value = DownDgv.Rows(index).Cells(i).Value
Next
End Sub
Private Sub DownDgv_Scroll(sender As Object, e As ScrollEventArgs) Handles DownDgv.Scroll
Try
If e.ScrollOrientation = ScrollOrientation.VerticalScroll Then
Dim topR As Integer = DownDgv.FirstDisplayedScrollingRowIndex
'If you want in top row the current value that is in the top uncomment this
SetChildValuesInTopRow(topR)
If listOfOwnerRows.Count > 0 Then
Dim rToSetAsOwner As Integer = listOfOwnerRows(listOfOwnerRows.Count - 1)
For i As Integer = listOfOwnerRows.Count - 1 To 0 Step -1
If listOfOwnerRows(i) <= topR Then
rToSetAsOwner = listOfOwnerRows(i)
Exit For
End If
Next
If rToSetAsOwner <> currentTopRow Then
SetFrosenRow(rToSetAsOwner)
End If
Console.WriteLine("rToSetAsOwner: " & rToSetAsOwner)
End If
Else
TopDgv.HorizontalScrollingOffset = DownDgv.HorizontalScrollingOffset
End If
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
End Sub
End Class
Usage:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Try
' first populate you grid putting a tag in each row which is a header/parent/title for other rows
TestPopulate()
Dim customControl As Control = New CustomDgv(DataGridView1)
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
End Sub
Sub TestPopulate()
For i As Integer = 0 To 100
DataGridView1.Rows.Add()
If i = 0 Then
DataGridView1.Rows.Item(0).Cells(0).Value = "Owner 0"
DataGridView1.Rows(0).Tag = "X"
End If
If i = 50 Then
DataGridView1.Rows.Item(50).Cells(0).Value = "Owner 50"
DataGridView1.Rows(50).Tag = "X"
End If
If i = 70 Then
DataGridView1.Rows.Item(70).Cells(0).Value = "Owner 70"
DataGridView1.Rows(70).Tag = "X"
End If
DataGridView1.Rows.Item(i).Cells(1).Value = "child_" & i.ToString & "_1"
DataGridView1.Rows.Item(i).Cells(2).Value = "child_" & i.ToString & "_2"
Next
End Sub
I hope I have been helpful

prevent go to next row when duplicated value in `datagridview`

I have datagrid that user will add values in just one column , and i want to prevent duplicated data in this column, i had mange that by the code bellow,
what I want is to keep the selection (focus) in the same editing cell(x)
if the entered data is duplicated, so I tried to get the current row index and return to it if the data is duplicated but its not working.
row_index = DataGridView1.CurrentRow.Index.ToString()
Dim cell As DataGridViewCell = DataGridView1.Rows(row_index).Cells(1)
DataGridView1.CurrentCell = cell
DataGridView1.BeginEdit(True)
NOTE : User will Add barcode number, so he will use barcode scanner or add it manually and press enter key.
Private Sub DataGridView1_RowValidated(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.RowValidated
If DataGridView1.Rows.Count > 2 Then
Dim i As Integer = 0
Dim row_index As Integer
' loop condition will loop while the row count is less or equal to i
While i <= DataGridView1.Rows.Count - 1
Dim j As Integer = 1
' loop condition will loop while the row count is less or equal to j
While j <= DataGridView1.Rows.Count - 1
Dim str As String = DataGridView1.Rows(i).Cells(1).Value()
Dim str1 As String = DataGridView1.Rows(j).Cells(1).Value()
If Not str1 = "" AndAlso Not str = "" Then
If str1 = str Then
'row_index = DataGridView1.SelectedCells.Item(i).RowIndex.ToString()
row_index = DataGridView1.CurrentRow.Index.ToString()
Dim cell As DataGridViewCell = DataGridView1.Rows(row_index).Cells(1)
DataGridView1.CurrentCell = cell
DataGridView1.BeginEdit(True)
Exit Sub
End If
End If
j += 1
End While
i += 1
End While
End If
End Sub
You can try it also in a for loop. This is how I do it. If what you mean is to stop/retain the selection(focus) or go to in a cell/row whenever it is a duplicate with the current data you have. This should work fine.
enter code here
For i = 0 To Datagridview1.Rows.Count - 1
If Datagridview1.Rows(i).Cells(1).Value = DataYouWillInput Then
DataGridView1.CurrentCell = DataGridView1.Rows(i).Cells(1)
Exit for
End If
Next
enter code here
If your condition returns true with the condition of current data and data you'll be adding. Just exit your loop. Use this.
DataGridView1.CurrentCell = DataGridView1.Rows(i).Cells(1)

Persisting DropDownList Value in PageIndexChanged of GridView

Protected Sub grdView_PageIndexChanging(sender As Object, e As GridViewPageEventArgs) Handles grdView.PageIndexChanging
grdView.SelectedIndex = -1
grdView.PageIndex = e.NewPageIndex
' To persist DDL values at paging using datatable
Dim Data As New DataTable
Data.Columns.Add("RowIndex", Type.GetType("System.Int32"))
Data.Columns.Add("SelectedValue", Type.GetType("System.String"))
For Each Row As GridViewRow In grdView.Rows
Dim ddl As DropDownList = DirectCast(Row.FindControl("ddlSample"), ComboBox)
If ddl.SelectedValue <> "" Then
Dim Rows As DataRow = Data.NewRow
Rows("RowIndex") = Row.RowIndex
Rows("SelectedValue") = ddl.SelectedValue
Data.Rows.Add(Rows)
End If
Next
' Passing the datatable to session
Session("MYDataTable") = Data
grdView.DataSource = grdDataSource
grdView.DataBind()
If Session("MYDataTable") IsNot Nothing AndAlso Session("MYDataTable") IsNot DBNull.Value Then
Data = CType(Session("MYDataTable"), DataTable)
For Each row In Data.Rows
If e.NewPageIndex = row("PageIndex") Then
Dim ddl As DropDownList = DirectCast(grdView.Rows(row("RowIndex")).FindControl("ddlSample"), DropDownList)
ddl.SelectedValue = row("SelectedValue")
End If
Next
End If
The above Code is the code I'm having for Persisting DropDownList value but it is not working as expected.
In my GridView i have two Columns
Details of First column : I have list of employee names
Details of Second Column : It has a dropDownlist in each row with many items in it.
In my grid i have nearly 100 values, So i have set allowPaging="true" and have set pagesize="10".
The problem what I'm facing is
Step 1 : I'm selecting a value in dropdownlist of rowindex 2 in page 0
Step 2 : changing the page to 5, the value I selected in page 0 for the rowindex 2 also appears in the page 5 for the rowindex 2 as per my code.
But what i want is
Step 1 : I'm selecting a value in dropdownlist of rowindex 2 in page 0
Step 2 : changing the page to 5, no value should be selected as i haven't selected any values in it.
Step 3 : I i go back again to Page 0 the value of ddl in Rowindex 2 should have the previously selected value.
EDIT
I'm peristing the Values in Dictionary as mentioned here..!!
Dim ddlValues As New Dictionary(Of String, Integer)
For rowIndex As Integer = 0 To grdOnlineVoter.Rows.Count
Dim ddl As ComboBox = grdView.Rows(rowIndex).FindControl("ddlsample")
If ddl IsNot Nothing Then
If ddl.SelectedIndex > 0 Then
Dim ddlIndex As Integer = rowIndex
ddlValues.Add(ddl.SelectedValue, ddlIndex)
End If
End If
Next
But i'm unable to repopulate it to the Dropdownlist
Alright, based on what you have displayed here I have reached this conclusion.
You are saving the values to the Dictionary to the specific Row number. That is 0-9. However, row numbers does not take pagenumber into consideration. So I recommend you to do the following: (Change is on row 6)
Dim ddlValues As New Dictionary(Of String, Integer)
For rowIndex As Integer = 0 To grdOnlineVoter.Rows.Count
Dim ddl As ComboBox = grdView.Rows(rowIndex).FindControl("ddlsample")
If ddl IsNot Nothing Then
If ddl.SelectedIndex > 0 Then
Dim ddlIndex As Integer = rowIndex + (GridView1.PageIndex * 10)
ddlValues.Add(ddl.SelectedValue, ddlIndex)
End If
End If
Next
Now page 1 will have values: 0-9
Page 2 will have values 10-19 etc.

VB.NET: How to dynamically select a list view item?

I need to dynamically select an item in a listview based on what was selected previously.
The items that have been selected in the past are retrieved from a database and added to an Arraylist. These items then need to be selected from a number of different listviews.
Doing this by index like so listRef1.Items(2).Checked = True is no problem but I need to do it by the item text, i.e. one of the strings in the array.
So far I have this:
For i As Integer = 0 To refsArr.Count - 1
'find the correct category id
Dim cmdRefCat As New SqlCommand("SELECT RefID from ReferencesListTable WHERE RefName = '" & refsArr(i) & "'", conn)
Dim refid As Integer = cmdRefCat.ExecuteScalar()
If refid = 1 Then
listRef1.Items(refsArr(i)).Checked = True
ElseIf refid = 2 Then
listRef2.Items(refsArr(i)).Selected = True
listRef2.Select()
ElseIf refid = 3 Then
listRef3.Items.Item(refsArr(i)).Selected = True
listRef2.Select()
ElseIf refid = 4 Then
listRef4.Items.Item(refsArr(i)).Selected = True
End If
Next
Has anyone got any ideas on this? Thanks.
You'll need to loop through each item in the listview list:
For I as Integer = 0 to ListView.Items.Count - 1 Do
If ListView.Items(i).Text = "Text" then
ListView.Items(i).Selected = true
End If
End For
You can try this ...
For i As Integer = 0 To refsArr.Count - 1
'find the correct category id
Dim cmdRefCat As New SqlCommand("SELECT RefID from ReferencesListTable WHERE RefName = '" & refsArr(i) & "'", conn)
Dim refid As Integer = cmdRefCat.ExecuteScalar()
Select case refid
case 1
CheckIt(refsArr(i),listRef1)
case 2
CheckIt(refsArr(i),listRef2)
case 3
CheckIt(refsArr(i),listRef3)
case 4
CheckIt(refsArr(i),listRef4)
End Select
Next
And Sub CheckIt
Sub CheckIt(ByVal sRef as String, ByRef lvw as Listview)
Dim x as Integer
For x = 0 to lvw.Items.Count - 1
If lvw.Items(x).Text = sRef then
lvw.Items(x).Selected = true
exit for '-- if only 1 record
End If
Next
End Sub
The code to select an item dynamically from the listview control can be as follows for vb.net.
Let lvwomominiChair1 is the name of the listview control.
Set its fullrowselect property as true.
The code will select the text in the first column of the listview control.
Private Sub lvwomominiChair1_Click(sender As Object,e As EventArgs) Handles lvwomominiChair1.Click
Dim lvwitem as ListViewItem
lvwitem = lvwomominiChair1.SelectedItems.Item(0)
MsgBox("Selected item is " + lvwitem.Text)
End Sub
There may be situations where we need to get all items in a row of a ListView control.The following code may be used for the purpose.It is assumed that there are five columns of data in a raw and are of the text data type.This can be done with a For..Next loop as follows.Let 0,1,2,3 and 4 are the five column indices.
Private Sub lvwomominiChair1_Click(sender As Object,e As EventArgs) Handles lvwomominiChair1.Click
Dim i As Int32
Dim str As String
str =""
For i =0 To 4
str = str + " " + lvwomominiChair1.SelectedItems(0).SubItems(i).Text
Next
MsgBox("Selected items of the five columns of the row are " + str)
End Sub
Or you can do this, works perfect for me:
ListView.Items(0).Selected = True
ListView.Select()