value of type integer cannot be converted to datatable vn.net - vb.net

i am trying to create tree view and some error i can not fix it
Sub CREATENODE()
Dim TRN As New TreeNode
Dim DT As New DataTable
DT.Clear()
DT = ACCOUNTTableAdapter.TREE_ACCOUNT()
For I As Integer = 0 To DT.Rows.Count - 1
If DT.Rows(I)(9).ToString() = "00000000-0000-0000-0000-000000000000" Then
TRN = New TreeNode(DT.Rows(I)(3).ToString() + " " + DT.Rows(I)(4).ToString())
TRN.Tag = DT.Rows(I)(1).ToString()
If DT.Rows(I)(7).ToString() <> "0" Then
TRN.ImageIndex = 0
TRN.SelectedImageIndex = 0
Else
TRN.ImageIndex = 1
TRN.SelectedImageIndex = 1
End If
TreeView1.Nodes.Add(TRN)
End If
Next
''For Each NODE As TreeNode In TreeView1.Nodes
'' CHELD(NODE)
'Next
End Sub

This is nonsense
Dim TRN As New TreeNode
Dim DT As New DataTable
DT.Clear()
DT = ACCOUNTTableAdapter.TREE_ACCOUNT()
You create a New TreeNode and then inside the loop you overwrite it with another New one. Just put the Dim inside the loop after the if.
Dim TRN = New TreeNode($"{row(3)} {row(4)}")
You create a brand new DataTable. Then you clear it when it can't possibly have anything in it. Then you throw it away and assign a different DataTable to it.
Just do
Dim DT = ACCOUNTTableAdapter.TREE_ACCOUNT()
I have simplified your code by using a For Each loop. Also, I used and interpolated string indicated by the $ preceding the string. Variables can be inserted in place surrounded by braces { }.
As far as the actual problem, you need to create an instance of your table adapter with the New keyword. Then call the appropriate method. A simple application will just use .GetData.
Private Sub CREATENODE()
Dim DT = (New ACCOUNTTableAdapter).TREE_ACCOUNT() 'See what intellisense offers. It may be just .GetData
For Each row As DataRow In DT.Rows
If row(9).ToString() = "00000000-0000-0000-0000-000000000000" Then
Dim TRN = New TreeNode($"{row(3)} {row(4)}")
TRN.Tag = row(1)
If row(7).ToString() <> "0" Then
TRN.ImageIndex = 0
TRN.SelectedImageIndex = 0
Else
TRN.ImageIndex = 1
TRN.SelectedImageIndex = 1
End If
TreeView1.Nodes.Add(TRN)
End If
Next
End Sub
Hint: Why not put the entire row in the Tag property. You will have access to all the fields by casting the Tag back to a DataRow.

Related

Assign value for each label name

Can someone teach me how to assign a value for each label with the same name?.
For example, I have a 10 label with the name label1 until label10. On each label,i want to show different value from sql. This is my code.
Dim sqlCmd As New SqlCommand("select distinct top 15 Machine_no from table5 ", conn)
Dim sqlDa As New SqlDataAdapter(sqlCmd)
sqlDa.Fill(dt)
If dt.Rows.Count > 0 Then
For i As Integer = 0 To dt.Rows.Count
lblMachine1.text = dt.Rows(0)("Machine_no").ToString)
lblMachine2.Text = dt.Rows(1)("Machine_no").ToString
lblMachine3.Text = dt.Rows(2)("Machine_no").ToString
lblMachine4.Text = dt.Rows(3)("Machine_no").ToString
lblMachine5.Text = dt.Rows(4)("Machine_no").ToString
lblMachine6.Text = dt.Rows(5)("Machine_no").ToString
lblMachine7.Text = dt.Rows(6)("Machine_no").ToString
lblMachine8.Text = dt.Rows(7)("Machine_no").ToString
lblMachine9.Text = dt.Rows(8)("Machine_no").ToString
lblMachine10.Text = dt.Rows(9)("Machine_no").ToString
lblMachine11.Text = dt.Rows(10)("Machine_no").ToString
lblMachine12.Text = dt.Rows(11)("Machine_no").ToString
lblMachine13.Text = dt.Rows(12)("Machine_no").ToString
lblMachine14.Text = dt.Rows(13)("Machine_no").ToString
lblMachine15.Text = dt.Rows(14)("Machine_no").ToString
Next
End If
The problem is, when no data in rows 5 for example, the system will give an error.
Welcome to the site!
Before we address your problem, I would like to point out that:
"The problem is, when no data in rows 5 for example, the system will
give an error."
is too broad to really identify your issue.
It would be very helpful to also include the error message you are receiving.
Regarding your real problem, your code can be shortened with the use of DirectCast. You can try this one:
If dt.Rows.Count > 0 Then
For i = 0 To dt.Rows.Count - 1
DirectCast(Controls.Find("lblMachine" & i + 1, True)(0), Label).Text = dt.Rows(i).Item("MachineNo").ToString
Next
End If
Using For Loop in your code is a good start but you didn't integrate it at all. In the code above, you can see how i is being used.
Also dt is a DataTable right? DataTables are index-based so it's starting with zero(0). That's why you can notice in the the For Loop statement the dt.Rows.Count - 1.
Hope it helps.
https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/for-each-next-statement
Also try searching for:
Vb.net for each control loop
You will more than likely have to make a direct object reference using a List(Of Label)
Here is my take on it. Untested.
Dim machList As List(Of Label) = New List(Of Label)
For Each label As Label In GroupBox1.Controls
machList.Add(label)
Next label
For row As Integer = 0 To dt.Rows.Count
If dt.Row(row) <> Nothing Then
machList.Index(row).Text = dt.Rows(row)
End If
Next row
You are using i as a loop variable but you are not using to reference your labels.
You can try to put your labels in an array and then match them up to a row by index like this:
Dim labels = {lblMachine1, lblMachine2, lblMachine3, lblMachine4,...}
Dim sqlCmd As New SqlCommand("select distinct top 15 Machine_no from table5 ", conn)
Dim sqlDa As New SqlDataAdapter(sqlCmd)
sqlDa.Fill(dt)
If dt.Rows.Count > 0 Then
For i As Integer = 0 To dt.Rows.Count -1
dim row= dt.rows(i)
labels(i).text = row("Machine_no")
Next
End If
You can also use FindControl for windows formas #Allen points out. But when using for Web you need to implement a recursive version because the control you are looking for is usually nested within some other control.
private FindControlRecursive(control parent, string id) as control
if parent.id=id then return parent
for each child in parent.controls
control result = FindControlRecursive(child, id)
if not result is nothing then return result
next
end function
Then in your code:
Dim sqlCmd As New SqlCommand("select distinct top 15 Machine_no from table5 ", conn)
Dim sqlDa As New SqlDataAdapter(sqlCmd)
sqlDa.Fill(dt)
If dt.Rows.Count > 0 Then
For i As Integer = 0 To dt.Rows.Count -1
fincontrolrecursive("lblMachine" + i).text = dt.rows(i)("Machine_no")
Next
End If

How to prevent adding repeated data into a listbox?

I have a bunch os items in lst1 which I want to put into lst2 but without repeating them on each ListBox.
Interface I'm using:
This is working, but you may need it to understand my doubt.
Dim dtTa_Enc As DataTable = New DataTable("Ta_Enc")
Dim dsTa As DataSet = New DataSet("Ta_E")
Dim adapter As New MySqlDataAdapter
Dim ds As DataSet = New DataSet
adapter.SelectCommand = New MySqlCommand
adapter.SelectCommand.Connection = connection
adapter.SelectCommand.CommandText = query
connection.Open()
adapter.Fill(ds, "tables")
connection.Close()
lst1.DataSource = ds.Tables("tables")
lst1.DisplayMember = "name"
lst1.ValueMember = "codta"
dtTa_Enc.Columns.Add("codta")
dtTa_Enc.Columns.Add("name")
dsTa.Tables.Add(dtTa_Enc)
lst2.DataSource = dsTa.Tables("Tables")
lst2.DisplayMember = "name"
lst2.ValueMember = "codta"
dtTa_Enc.Rows.Add(lst1.ValueMember, lst1.GetItemText(lst1.SelectedItem))
Doubt:
Now, The user presses a button to add his selected item of lst1 to lst2. Easy! However, what if he tries to add the same item. Can VB.Net stop him from doing it?
If not dtTa_Enc.find("codTa = " + lst1.valuemember) Then
dtTa_Enc.Rows.Add(lstTabelas.ValueMember, lstTabelas.GetItemText(lstTabelas.SelectedItem))
End If
Under the Add event handler, you could place some logic at the begining to prevent adding the repeated item.
Dim lst1Selected As String = CType(lst1.SelectedItem, DataRowView)("name").ToString
Dim flag As Integer = 0
For Each item As Object In lst2.Items
Dim istr As String = CType(item, DataRowView)("name").ToString
If istr = lst1Selected Then
flag = 1
Exit For
End If
Next
If flag = 1 Then
Exit Sub
End If
You can enumerate through your lst2 to determine whether any of the values match your selected item, lst1.SelectedItem.
So loop,
Dim found As Boolean = False
For Each itm As String in lst2.Items
If itm = lst1.SelectedItem Then
found = True
End If
Next
If Not found Then
'Add it.
End If
Or you can simply use the Contains method:
If Not lst2.Items.Contains(lst1.SelectedItem) Then
'Add it.
End if.

letting user type and add value to an already bound combobox

I have one combobox in my app that gets populated with a dozen or so items from SQL SERVER. I am currently trying to allow user to be able to type in a new value into the combobox and save it to a table in SQL SERVER. I'm looking for something along the lines of a DropDownStyle of DropDown and DropDownList. Basically I'm hoping to let the user type in the combobox, however if the value is not there, i want to be able to give them an option of saving it (probably on lost focus). I'm wondering what would be a good way of doing something like that.
On lost focus should I basically go through each item that is currently in the drop down and check it against the value entered?
EDIT:
Sql="SELECT IDvalue, TextName from TblReference"
Dim objconn As New SqlConnection
objconn = New SqlConnection(conn)
objconn.Open()
Dim da As New SqlDataAdapter(sql, objconn)
Dim ds As New DataSet
da.Fill(ds, "Name")
If ds.Tables("Name").Rows.Count > 0 Then
Dim dr As DataRow = ds.Tables("Name ").NewRow
ds.Tables("Name").Rows.InsertAt(dr, 0)
With c
.DataSource = ds.Tables("Name")
.ValueMember = " IDvalue "
.DisplayMember = " TextName "
End With
End If
You are already adding a fake/blank row to a table, you can do the same thing for a new item.
' form level datatable var
Private cboeDT As DataTable
Initializing:
cboeDT = New DataTable
Dim sql = "SELECT Id, Descr FROM TABLENAME ORDER BY Descr"
Using dbcon As New MySqlConnection(MySQLConnStr)
Using cmd As New MySqlCommand(sql, dbcon)
dbcon.Open()
cboeDT.Load(cmd.ExecuteReader())
' probably always need this even
' when there are no table rows (???)
Dim dr = cboeDT.NewRow
dr("Id") = -1 ' need a way to identify it
dr("Descr") = ""
cboeDT.Rows.InsertAt(dr, 0)
End Using
End Using
cboeDT.DefaultView.Sort = "Descr ASC"
cboE.DataSource = cboeDT
cboE.DisplayMember = "Descr"
cboE.ValueMember = "Id"
Note Users tend to have a preference as to the order of these things. The simple creatures tend to prefer alphabetical over a DB Id they may never see. To accommodate them, the DefaultView is sorted so that any new rows added will display in the correct order.
Add new items in the Leave event (much like Steve's):
Private Sub cboE_Leave(sender ...
' if it is new, there will be no value
If cboE.SelectedValue Is Nothing Then
' alternatively, search for the text:
'Dim item = cboeDT.AsEnumerable().
' FirstOrDefault(Function(q) String.Compare(q.Field(Of String)("Descr"),
' cboE.Text, True) = 0)
'If item Is Nothing Then
' ' its new...
Dim newid = AddNewItem(cboE.Text)
Dim dr = cboeDT.NewRow
dr("Id") = newid
dr("Descr") = cboE.Text
cboeDT.Rows.Add(dr)
' fiddling with the DS looses the selection,
' put it back
cboE.SelectedValue = newid
End If
End Sub
If you want to search by text:
Dim item = cboeDT.AsEnumerable().
FirstOrDefault(Function(q) String.Compare(q.Field(Of String)("Descr"),
cboE.Text, True) = 0)
If item Is Nothing Then
' its new...
...
Inserting will vary a little depending on the actual db. A key step though is to capture and return the ID of the new item since it is needed for the CBO:
Private Function AddNewItem(newItem As String) As Int32
Dim sql = "INSERT INTO MY_TABLE (Descr) VALUES (#v); SELECT LAST_INSERT_ID();"
Dim newId = -1
Using dbcon As New MySqlConnection(MySQLConnStr)
Using cmd As New MySqlCommand(sql, dbcon)
dbcon.Open()
cmd.Parameters.Add("#v", MySqlDbType.String).Value = newItem
' MySql provides it in the command object
If cmd.ExecuteNonQuery() = 1 Then
newId = Convert.ToInt32(cmd.LastInsertedId)
End If
End Using
End Using
Return newId
End Function
As noted MySql provides the LastInsertedID as a command object property. In SQL SERVER, tack ...";SELECT LAST_INSERT_ID();" to the end of your SQL and then:
newId = Convert.ToInt32(cmd.ExecuteScalar())
This is not conceptually very different from Steve's answer, except it uses the DataTable you build rather than collections which makes it (very) slightly simpler.
The way I do this, is on window load I perform a new SQL query to get the list of values in the table, and load them into a combobox.
Then once focus is lost, it then checks what's currently typed into the combobox against the current values already loaded. If it doesn't exist, then it's not in SQL. Something like the following...
Dim found As Boolean = False
For i As Integer = 0 To comboBox.Items.Count - 1
Dim value As String = comboBox.Items(i).ToString()
If comboBox.Text = value Then
found = True
End If
Next
If found = False Then
'the item doesn't exist.. add it to SQL
Else
'the item exists.. no need to touch SQL
End If
First thing I would do is to build a simple class to hold your values through a List of this class
Public Class DataItem
Public Property IDValue As Integer
Public Property TextName as String
End Class
Now, instead of building an SqlDataAdapter and fill a dataset, work with an SqlDataReader and build a List(Of DataItem)
' Class global...
Dim allItems = new List(Of DataItem)()
Sql="SELECT IDvalue, TextName from TblReference"
' Using to avoid leaks on disposable objects
Using objconn As New SqlConnection(conn)
Using cmd As New SqlCommand(Sql, objconn)
objconn.Open()
Using reader = cmd.ExecuteReader()
While reader.Read()
Dim item = new DataItem() With { .IDValue = reader.GetInt32(0), .TextName = reader.GetString(1)}
allItems.Add(item)
End While
End Using
if allItems.Count > 0 Then
allItems.Insert(0, new DataItem() With {.IDValue = -1, .TextValue = ""}
Dim bs = new BindingList(Of DataItem)(allItems)
c.DataSource = bs
c.ValueMember = "IDvalue"
c.DisplayMember = "TextName"
End If
End Using
End Using
Now the code that you want to add to your Leave event for the combobox
Sub c_Leave(sender As Object, e As EventArgs) Handles c.Leave
If Not String.IsNullOrEmpty(c.Text) Then
Dim bs = DirectCast(c.DataSource, BindingList(Of DataItem))
if bs.FirstOrDefault(Function(x) x.TextName = c.Text) Is Nothing Then
Dim item = new DataItem() With { .IDValue = -1, .TextName = c.Text}
bs.Add(item)
' here add the code to insert in the database
End If
End If
End Sub

VB: Count number of columns in csv

So, quite simple.
I am importing CSVs into a datagrid, though the csv always has to have a variable amount of columns.
For 3 Columns, I use this code:
Dim sr As New IO.StreamReader("E:\test.txt")
Dim dt As New DataTable
Dim newline() As String = sr.ReadLine.Split(";"c)
dt.Columns.AddRange({New DataColumn(newline(0)), _
New DataColumn(newline(1)), _
New DataColumn(newline(2))})
While (Not sr.EndOfStream)
newline = sr.ReadLine.Split(";"c)
Dim newrow As DataRow = dt.NewRow
newrow.ItemArray = {newline(0), newline(1), newline(2)}
dt.Rows.Add(newrow)
End While
DG1.DataSource = dt
This works perfectly. But how do I count the number of "newline"s ?
Can I issue a count on the number of newlines somehow? Any other example code doesn't issue column heads.
If my csv file has 5 columns, I would need an Addrange of 5 instead of 3 and so on..
Thanks in advance
Dim sr As New IO.StreamReader(path)
Dim dt As New DataTable
Dim newline() As String = sr.ReadLine.Split(","c)
' MsgBox(newline.Count)
' dt.Columns.AddRange({New DataColumn(newline(0)),
' New DataColumn(newline(1)),
' New DataColumn(newline(2))})
Dim i As Integer
For i = 0 To newline.Count - 1
dt.Columns.AddRange({New DataColumn(newline(i))})
Next
While (Not sr.EndOfStream)
newline = sr.ReadLine.Split(","c)
Dim newrow As DataRow = dt.NewRow
newrow.ItemArray = {newline(0), newline(1)}
dt.Rows.Add(newrow)
End While
dgv.DataSource = dt
End Sub
Columns and item values can be added to a DataTable individually, using dt.Columns.Add and newrow.Item, so that these can be done in a loop instead of hard-coding for a specific number of columns. e.g. (this code assumes Option Infer On, so adjust as needed):
Public Function CsvToDataTable(csvName As String, Optional delimiter As Char = ","c) As DataTable
Dim dt = New DataTable()
For Each line In File.ReadLines(csvName)
If dt.Columns.Count = 0 Then
For Each part In line.Split({delimiter})
dt.Columns.Add(New DataColumn(part))
Next
Else
Dim row = dt.NewRow()
Dim parts = line.Split({delimiter})
For i = 0 To parts.Length - 1
row(i) = parts(i)
Next
dt.Rows.Add(row)
End If
Next
Return dt
End Function
You could then use it like:
Dim dt = CsvToDataTable("E:\test.txt", ";"c)
DG1.DataSource = dt

Converting Gridview to DataTable in VB.NET

I am using this function to create datatable from gridviews. It works fine with Gridviews with AutoGenerateColumns = False and have boundfields or template fileds. But if I use it with Gridviews with AutoGenerateColumn = True I only get back an empty DataTable. Seems Gridview viewstate has been lost or something. Gridview is binded on PageLoad with If Not IsPostback. I can't think of anything else to make it work. Hope someone can help me.
Thanks,
Public Shared Function GridviewToDataTable(gv As GridView) As DataTable
Dim dt As New DataTable
For Each col As DataControlField In gv.Columns
dt.Columns.Add(col.HeaderText)
Next
For Each row As GridViewRow In gv.Rows
Dim nrow As DataRow = dt.NewRow
Dim z As Integer = 0
For Each col As DataControlField In gv.Columns
nrow(z) = row.Cells(z).Text.Replace(" ", "")
z += 1
Next
dt.Rows.Add(nrow)
Next
Return dt
End Function
Slight modification to your function above. If the autogenerate delete, edit or select button flags are set, the values for the fields are offset by one. The following code accounts for that:
Public Shared Function GridviewToDataTable(ByVal PassedGridView As GridView, ByRef Error_Message As String) As DataTable
'-----------------------------------------------
'Dim Tbl_StackSheets = New Data.DataTable
'Tbl_StackSheets = ReportsCommonClass.GridviewToDataTable(StackSheetsGridView)
'-----------------------------------------------
Dim dt As New DataTable
Dim ColInd As Integer = 0
Dim ValOffset As Integer
Try
For Each col As DataControlField In PassedGridView.Columns
dt.Columns.Add(col.HeaderText)
Next
If (PassedGridView.AutoGenerateDeleteButton Or PassedGridView.AutoGenerateEditButton Or PassedGridView.AutoGenerateSelectButton) Then
ValOffset = 1
Else
ValOffset = 0
End If
For Each row As GridViewRow In PassedGridView.Rows
Dim NewDataRow As DataRow = dt.NewRow
ColInd = 0
For Each col As DataControlField In PassedGridView.Columns
NewDataRow(ColInd) = row.Cells(ColInd + ValOffset).Text.Replace(" ", "")
ColInd += 1
Next
dt.Rows.Add(NewDataRow)
Next
Error_Message = Nothing
Catch ex As Exception
Error_Message = "GridviewToDataTable: " & ex.Message
End Try
Return dt
End Function