InvalidCastException was unhandled in VB.NET - vb.net

Referring to this question: StackOverflowException was unhandled in VB.NET I decided to create a new question because I have a new error.
Unable to cast object of type 'System.Windows.Forms.BindingSource' to type 'System.Data.DataTable'.
CODE (in button click event):
' Copy rows from the first datagridview to the second datagridview that is data bound
' First copy the second datagridviews datasource into a new data table
Dim dt As DataTable = CType(frmEncodeDatabase.EncodingDataGridView.DataSource, DataTable).Copy
Dim dr As DataRow
' Loop through all rows of the first datagridview and copy them into the data table
For r As Int32 = 0 To Me.DataGridViewX1.Rows.Count - 1
If Me.DataGridViewX1.Rows(r).IsNewRow = False Then ' Do not copy the new row
dr = dt.NewRow
' Loop through all cells of the first datagridview and populate the data row
For c As Int32 = 0 To Me.DataGridViewX1.ColumnCount - 1
dr(c) = Me.DataGridViewX1.Rows(r).Cells(c).Value
Next
dt.Rows.Add(dr) ' Add the data row to the data table
End If
Next
Me.DataGridView2.DataSource = dt ' Rebind the second datagridview with the new table which has all the rows from both datagridviews
frmEncodeDatabase.show()
The error, which is in the image, is in dt As DataTable = CType(frmEncodeDatabase.EncodingDataGridView.DataSource, DataTable).Copy where the error is right now. How will I modify the code?

The error message is self-explainable.
"Unabled to cast object of type 'BindingSource' to type 'DataTable'."
The datassource of your datagridview is a BindingSource, so you need to cast to this type.
Dim bs As BindingSource = CType(frmEncodeDatabase.EncodingDataGridView.DataSource, BindingSource)
Assuming that the datasource of the bindingsource is a datatable:
Dim dt As DataTable = CType(bs.DataSource, DataTable)
If not, you'll get another cast exception, but now you how to fix it.

Related

ComboBoxColumn errors out when trying to load data

I am trying to create a DataGridView with a DataGridViewComboBox
I am using the following code to generate it using 2 function that return DataTables for populating it:
'// Returns a DataTable with 2 Columns of Type Integer and System.String
'// Column 1 are IDs called ID, Column 2 is a String of numbers called CompanyCode
'// Example:
'// 1,'9999'
'// 2,'9998'
'// 3,'9997' etc.
Dim uTableSys As DataTable = GetCompanyCodeLinks()
'// Returns a DataTable with 1 Column of Type System.String
'// The Column is called CC
'// Example: '0001','0002','1234'
Dim CompanyCodes As DataTable = GetListCompanyCodes()
Dim uBindSys As New BindingSource
uBindSys.DataSource = uTableSys
Dim uCol1 As New DataGridViewComboBoxColumn()
uCol1.HeaderText = "Buchungskreis"
'// Points to uTableSys.CompanyCode
uCol1.DataPropertyName = "CompanyCode"
uCol1.DataSource = CompanyCodes
uCol1.ValueType = uTableSys.Columns(1).DataType
'// Points to CompanyCodes.CC
uCol1.ValueMember = "CC"
uCol1.DisplayMember = uCol1.ValueMember
Me.DGV.Columns.Add(uCol1)
Me.DGV.AutoGenerateColumns = False
Me.DGV.DataSource = uBindSys
But as soon as I add uCol1.DataPropertyName = "CompanyCode", which I assume would link the DGV Column to the BindingSource table "CompanyCode" column, it returns with the following error:
"The DataGridViewComboBoxCell value is not valid"
I have checked the types of the DataTable, which are System.String, which the Column is set to via the uCol1.ValueType in the code. For clarification, uTableSys.Columns(1).DataType returns System.String
So why does it return with a "value is not valid" error?
I have figured out the issue:
The value that is written in the cell from the GridView DataSource on loading has to exist ComboBox list as well. If the value does not exist, it will throw the error.

VB.Net Programmatically set DataGridViewComboBox .ValueMember on Rows.Add

I am trying to programmatically set the value of a DataGridViewComboBox when I populate the grid, but I keep getting an error about not being able to sort the combobox - "ComboBox that has a DataSource set cannot be sorted. Sort the data using the underlying data model."
I am not trying to sort the data of the combobox, I am simply trying to set the value member when I perform the Rows.Add function.
EDIT** The entire column should contain the same combobox items, and is not row specific.
Public Sub LoadComboBox()
Dim comboBox = New Dictionary(Of Integer, String)
Try
//myStepTable = data ' SQL query to get ID and Step
For Each row As DataRow In myStepTable.Rows
comboBox.Add(row.Item("StepID"), row.Item("Step"))
Next
'colStep is the defined name of the combobox column
colStep.DataSource = New BindingSource(comboBox, Nothing)
colStep.DisplayMember = "Value"
colStep.ValueMember = "Key"
End Sub
Public Sub LoadGrid()
LoadComboBox()
myDataTable = data 'SQL query to get row data
For Each row As DataRow In myDataTable.Rows
dgvRecipeSteps.Rows.Add(row.Item("RowID"), row.Item("StepID"))
Next
End Sub

datatable is empty vb.net

I'm not familiar with .net languages. but I tried to copy a datagridview rows to a datatable.when I use Watch on my datatable it has values but when i try to watch dataset,my datatable is empty. here is my code :
Dim dt As New DataTable("repTable")
For Each col As DataGridViewColumn In dgrMatchesExacutives.Columns
dt.Columns.Add(col.HeaderText)
Next
For Each row As DataGridViewRow In dgrMatchesExacutives.Rows
Dim dRow As DataRow = dt.NewRow()
For Each cell As DataGridViewCell In row.Cells
dRow(cell.ColumnIndex) = cell.Value
Next
dt.Rows.Add(dRow)
Next
If ds.Tables.Contains("repTable") Then
ds.Tables.Remove("repTable")
End If
ds.Tables.Add("repTable")
The Tables property of the DataSet is a DataTableCollection and you add items to this collection using the provided overloads of the Add method. But if you call the overload that receives a string you CREATE a NEW datatable (empty of course). The fact that you call the created datatable with the same name of the existing one has no relevance for the dataset.
If you have manually created a datatable and prepared it yourself with a schema and records then you need to use the overload that takes a DataTable
ds.Tables.Add(dt)

vb.net working with multiple controls added at runtime

I am adding a tab page and datagridview to a Tab Control for every record in a datatable.
I would like to have a new Tab/DataGridView for each record (there will be ~3 for right now). I am declaring a new DataGridView D. How do I refer to these controls later?
I will want to do things like save changes in the datagridview to the database. Currently I can get the data on the screen and it looks good, but I believe I am not adding the DataGridView controls correctly because I keep re-using "D" as the control.
Dim dt As New DataTable
GetDataTable("SELECT * FROM aFeeTypes DescSeq", dt)
Dim i As Integer
'for each class in the datatable add a tab and a datagridview
For i = 0 To dt.Rows.Count - 1
Dim dr As DataRow
dr = dt.Rows(i)
Dim D = New DataGridView
D.Visible = True
Dim tp As New TabPage
tp.Name = "tp" & i
tp.Text = dr.Item("Desc2")
frmUI.tcFee.TabPages.Add(tp)
frmUI.tcFee.TabPages(i).Controls.Add(D)
dgv_Fill(D, "SELECT * FROM Fee WHERE ClassID=" & dr.Item("ClassID") & " ORDER BY Seq")
D.AutoResizeColumns()
D.Width = tp.Width
D.Height = tp.Height
Next i
this does not work:
With frmUI.Controls("D" & i)
.AutoResizeColumns()
.Width = tp.Width
.Height = tp.Height
End With
D is purely the variable name in the scope you are using it in.
You need to give the control a unique Name that yo can reference it by later.
The Name property can be used at run time to evaluate the object by
name rather than type and programmatic name. Because the Name property
returns a String type, it can be evaluated in case-style logic
statements (Select statement in Visual Basic, switch statement in
Visual C# and Visual C++).
I found a solution to the problem. The problem is that the new row has an autonumber ID.
When da.update(dt) occurs, the new row is inserted to the database. The database knows the new autonumber ID. However, the datatable does not.
For the datatable to know, the dataadapter is refilled. However, this causes the datatable to have all the old rows plus all the new rows and they all appear in the datagridview.
By clearing the old rows from the datatable, the fill refreshes all the data in the datatable and therefore refreshes the datagridview.
Public Sub dgv_AddRow(ByVal dgvName As String)
Dim dgv As DataGridView = colDataGridView.Item(dgvName)
Dim da As SqlDataAdapter = colDataAdapter.Item(dgvName)
Dim dr As DataRow = frmUI.allDataSet.Tables(dgvName).NewRow
'autopopulate the class id
dr("ClassID") = dgv.Parent.Tag
'add the new row
frmUI.allDataSet.Tables(dgvName).Rows.Add(dr)
'get the changed table
Dim dt As DataTable = frmUI.allDataSet.Tables(dgvName)
'inserts the new row to the database. concurrency violation
'will occur because datatable does not know the new Autonumber ID for the new row.
da.Update(dt)
'remove the datatable rows so they can be replaced using the adapter fill
'if rows are not cleared, following fill causes datatable to
'have existing rows plus all the rows again due to the fill
frmUI.allDataSet.Tables(dgvName).Rows.Clear()
'refill the adapter (refill the table)
'Everything you do to the underlying dataTable
'gets displayed instantly on the datagridview
da.Fill(frmUI.allDataSet, dgvName)
End Sub

How to populate the Combobox in VBdotNet

How to pupolate the Combobox in VB.Net, the items are from DataSet... Here's my code
Dim LibDSPopulate As New DataSet
Dim LibDAPopulate As OdbcDataAdapter = New OdbcDataAdapter("SELECT DISTINCT Category FROM tblBooks", LibConn)
LibDAPopulate.Fill(LibDSPopulate, "tblBooks")
cmbCategoryF.Items.Add(LibDSPopulate)
You may use Data binding facility.
'Add an empty entry
Dim dr As DataRow = LibDSPopulate.Tables("tblBooks").NewRow
dr("Category") = "***Select***"
LibDSPopulate.Tables("tblBooks").Rows.InsertAt(dr, 0)
cmbCategoryF.DataSource=LibDSPopulate.Tables("tblBooks")
cmbCategoryF.DisplayMember="Category" 'Name of field
cmbCategoryF.ValueMember="Category" 'Name of field
If you don't want to use databindng then add each item using Items.Add() method.
 For Each row As DataRow In LibDSPopulate.Tables("tblBooks").Rows
ComboBox1.Items.Add(row("Category"))
Next