VB.NET load Datagridview thrown exception while calling it from different thread - vb.net

Firstly sorry for my bad English.
My problem is when I'm load data from different thread cause "Object reference not set to an instance of an object."
Here is my code :
Private Sub GetData(ByVal startRecord As Integer, ByVal maxRecord As Integer)
Dim ds As DataSet = New DataSet()
Dim da As MySqlDataAdapter = New MySqlDataAdapter("select * from my_data", SqlCon)
Try
da.Fill(ds, startRecord, maxRecord, "my_data")
ds.Tables("my_data").DefaultView.AllowNew = False
dgv.DataSource = ds.Tables("my_data")
For Each col As Object In dgv.Columns
If TypeOf col Is DataGridViewCheckBoxColumn Then
DirectCast(col, DataGridViewCheckBoxColumn).Visible = False
ElseIf TypeOf col Is DataGridViewImageColumn Then
DirectCast(col, DataGridViewImageColumn).Visible = False
ElseIf TypeOf col Is DataGridViewTextBoxColumn Then
Dim tbc As DataGridViewTextBoxColumn = CType(col, DataGridViewTextBoxColumn)
If tbc.Name = "no" Then
tbc.Width = 40
tbc.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
tbc.HeaderText = "No"
ElseIf tbc.Name = "ID" Then
tbc.Width = 110
tbc.HeaderText = "ID"
ElseIf tbc.Name = "name" Then
tbc.Width = 290
tbc.HeaderText = "Name"
ElseIf tbc.Name = "Address" Then
tbc.Width = 230
tbc.HeaderText = "Address"
Else
tbc.Visible = False
End If
End If
Next
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
The problem is here :
dgv.DataSource = ds.Tables("my_data")
So, what's wrong with my codes? It's always getting error when calling it from multithreading method, but when i put in on the button it's work fine.

It's always getting error when calling it from multithreading method,
but when i put in on the button it's work fine.
Your GetData() method is obviously not located in your Form, so it has no idea who "dgv" is. One solution would be to pass the DataGridView just like your other parameters.
Change:
Private Sub GetData(ByVal startRecord As Integer, ByVal maxRecord As Integer)
To:
Private Sub GetData(ByVal dgv As DataGridView, ByVal startRecord As Integer, ByVal maxRecord As Integer)
Then the call (in your Form) would look like this:
GetData(dgv, someValue, someOtherValue)

what vb is saying to you is that the variable you are trying to use hasn't nothing in it. you need to set it to point at something.
no where in your code have you specified what dvg is and you haven't carried the dvg over into the subroutine.
so you should have dim dvg as something = something or dim dvg as new something = new something

Related

Binding a Long/Int64 field to NumericUpdown leads to OleDbException "Too few parameters" on update

I am stuck with this problem the whole day, so maybe someone has a tip for me.
The environment: MS Access DB, VB.NET, OleDb-Driver, MS Access Database Engine 2016.
I am trying to bind a Long/Int64 field to a NumericUpDown control, but on update I get always the OleDbException "Too few parameters". I am pretty sure that the long field is the problem, because when I delete it from the table (and comment out the code for it) everything works fine. I am not sure that a NumericUpDown is suitable for this task, but it's underlying datatype is decimal and decimal has way more space as a long needs. So here is some code:
In the DataLayer:
Private Sub InitializeDataSet()
Dim LocFields = String.Join("], [", Fields)
Dim SQL As String = "SELECT [" & LocFields & "] FROM [" & Table & "]"
DAMain = New OleDbDataAdapter(SQL, Connection)
Using Builder As New OleDbCommandBuilder(DAMain) With {
.ConflictOption = ConflictOption.OverwriteChanges
}
Builder.GetInsertCommand()
Builder.GetUpdateCommand()
Builder.GetDeleteCommand()
End Using
DS = New DataSet
DAMain.Fill(DS, Table)
End Sub
Public Sub Update()
DAMain.Update(DS, Table) ' <-- Here the exception happens
End Sub
Public ReadOnly Property DataSource As Object
Get
Return DS
End Get
End Property
Public ReadOnly Property DataMember As String
Get
Return Table
End Get
End Property
We are here in a class, so the variables are:
Table = the name of the table
Fields = the list of the fields in the table
Connection = the OleDbConnection
DAMain = the OleDbDataAdapter
DS = the DataSet
In the Form:
Private DL As OleDbDataLayer
Private WithEvents BSource As New BindingSource
Public Sub New(DataLayer As OleDbDataLayer)
InitializeComponent()
DL = DataLayer
BSource.DataSource = DL.DataSource
BSource.DataMember = DL.DataMember
BSource.AllowNew = True
BSource.Sort = DL.OrderBy
BSource.Position = 0
InitializeFields()
End Sub
Private Sub DataUpdate()
BSource.EndEdit()
DL.Update()
End Sub
Private Sub InitializeFields()
NUD.Minimum = Long.MinValue
NUD.Maximum = Long.MaxValue
Dim Binding As New Binding("Value", BSource, "F_Long")
AddHandler Binding.Format, AddressOf FormatDBNull
AddHandler Binding.Parse, AddressOf ParseNumericUpDown
NUD.DataBindings.Add(Binding)
End Sub
Private Sub FormatDBNull(sender As Object, e As ConvertEventArgs)
If Convert.IsDBNull(e.Value) Then
Select Case e.DesiredType
Case = GetType(Decimal) : e.Value = 0
Case = GetType(Date) : e.Value = Today
Case = GetType(Boolean) : e.Value = False
Case Else
End Select
End If
End Sub
Private Sub ParseNumericUpDown(sender As Object, e As ConvertEventArgs)
Select Case e.DesiredType
Case = GetType(Byte)
e.Value = Convert.ToByte(e.Value)
Case = GetType(Short)
e.Value = Convert.ToInt16(e.Value)
Case = GetType(Integer)
e.Value = Convert.ToInt32(e.Value)
Case = GetType(Long)
e.Value = Convert.ToInt64(e.Value)
Case Else
' Do Nothing
End Select
End Sub
Here NUD is the NumericUpDown control which should be obvious.
Maybe I should use another control type? TextBox? MaskedTextBox?

Using corresponding value of picturebox to delete access record

Hey I've created a dictionary that I use to create pictureboxes. Each picturebox has a number, which I then want to use to remove the access record, corresponding to that number. So I've got the dictionary working, but how do I get the number that corresponds to each picturebox? Here is my code (everything is defined, like cardsdictionary as dictionary):
Public Sub bigpictureloader()
'Dim list As New List(Of String)(cardsdictionary.Keys)
Dim cardcount As Integer
cardcount = 0
counter += 1
cardcount = counter
'Dim cards As List(Of String) = New List(Of String)
cardsdictionary.Add(imageurltxt.Text, cardcount)
'Create a placeholder variable
Dim cardPictureBox As PictureBox
Dim pair As KeyValuePair(Of String, Integer)
'Loop through every selected card URL
For Each pair In cardsdictionary
'Create a new PictureBox
cardPictureBox = New PictureBox()
cardPictureBox.Size = New Size(100, 100)
cardPictureBox.SizeMode = PictureBoxSizeMode.Zoom
cardPictureBox.WaitOnLoad = False
AddHandler cardPictureBox.Click, AddressOf imagehandler
'Add the PictureBox to the Form
Me.Controls.Add(cardPictureBox)
'MsgBox(cardsdict.Values.ToString)
If imageurltxt.Text = "" Then
cardPictureBox = Nothing
Else
cardPictureBox.LoadAsync(pair.Key)
TableLayoutPanel1.Controls.Add(cardPictureBox, 0, 0)
End If
Next
End Sub
Private Sub testdelete()
'THIS SAVES TO THE DEBUG ACCESS DATABASE!!!!!
Using conn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source = FULL YUGIOH ACCESS DATABASE.accdb;")
Using command As New OleDbCommand("Delete From cmon11 Where ID= #ID;", conn)
'pair.value is what I think will work, but doesn't currently
command.Parameters.Add("#ID", OleDbType.Integer).Value = CInt(pair.value)
conn.Open()
command.ExecuteNonQuery()
End Using
End Using
End Sub
this is my imagehandler!!!
Private Sub imagehandler(Sender As Object, e As EventArgs)
testdelete()
End Sub
You can use the Tag property of the PictureBox to store the ID. You populate this property when you create the PictureBox.
In your handler you can do something like this:
Private Sub imagehandler(Sender As Object, e As EventArgs)
Dim myPictureBox As PictureBox = CType(sender, PictureBox)
'Now you can access myPictureBox.Tag and pass it into your delete function
Dim id As Integer = -1
If Int32.TryParse(myPictureBox.Tag, id) = True Then
testdelete(id)
End If
End Sub
Private Sub testdelete(id As Integer)
'THIS SAVES TO THE DEBUG ACCESS DATABASE!!!!!
Using conn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source = FULL YUGIOH ACCESS DATABASE.accdb;")
Using command As New OleDbCommand("Delete From cmon11 Where ID= #ID;", conn)
'pair.value is what I think will work, but doesn't currently
command.Parameters.Add("#ID", OleDbType.Integer).Value = id
conn.Open()
command.ExecuteNonQuery()
End Using
End Using
End Sub
testdelete doesn't know which imasge you want to delete. Using Michael's suggestion you want:
command.Parameters.Add("#ID", OleDbType.Integer).Value = CInt(Me.Tag)
By the way your use of counter and cardcount can be cleaned up substantially.

How to use a GetType and pass it to a function

why doesn't passing a datatype of an object to a function work? and how do you get around it?
Dim MyObj as new CustomObj
Dim t As Type = MyObj.GetType
Call My_Fuction(Of t)
I'm saving serializable objects to file, then open them up later on, and then the code needs to find the UI based on the object datatype, so it can populate the UI from the object
Private Function My_Fuction(Of t As Base_Object)() As UserControl
Dim UI_Type As Type = GetType(UI_Common_Panel(Of t))
For Each Object_type As Type In Project_Solution.GetTypes()
For Each Itype As Type In Object_type.GetInterfaces()
If Itype Is UI_Type Then Return DirectCast(Activator.CreateInstance(Object_type), UI_Common_Panel(Of t))
Next
Next
Return Nothing
End Function
It is difficult to give a good answer because you have all custom classes in your question. If the problem you are trying to solve is to create a new control based on the object's Type, here is a way to do that using built-in controls:
Function GetControl(o As Object) As Control
If o.GetType Is GetType(Boolean) Then
Return New CheckBox With {.Checked = DirectCast(o, Boolean)}
ElseIf o.GetType Is GetType(Date) Then
Return New DateTimePicker With {.Value = DirectCast(o, Date)}
ElseIf o.GetType Is GetType(String) Then
Return New TextBox With {.Text = DirectCast(o, String)}
Else
Return New TextBox With {.Text = o.ToString}
End If
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim c As Control = GetControl("Hello, world!")
Me.Controls.Add(c)
c.Visible = True
Dim c2 As Control = GetControl(#05/04/2017#)
Me.Controls.Add(c2)
c2.Visible = True
c2.Top = 100
End Sub

DatagridView VB.Net, thread safety

So i have this DataTable i have to show in a datagridview.
To do this i used to do the following line in the form_load
Me.Datagridview1.datasource = DT
It will work if i have to add a few rows, but when i add enough to make the scrollbar in the datagridview appear, it will freeze de program. No exceptions are thrown but my program will freeze and i think it is because im learning how to use threads.
Here i start listening another program that will send strings and i have to split them and put them into rows inside a datatable, and then show them.
Private Vstm As Stream
Dim tcp As New TcpClient
Dim DT As New DataTable("Acciones")
Dim Inter As New Interprete
Private Sub Conectar_Click(sender As Object, e As EventArgs) Handles Button1.Click
tcp.Connect("192.168.1.143", 8050)
Vstm = tcp.GetStream()
Dim VtcpThd As New Thread(AddressOf LeerSocket)
'Se arranca el subproceso.
VtcpThd.Start()
End Sub
Here in LeerSocket ill do the reading
Private Sub LeerSocket()
Dim VbufferDeLectura() As Byte
VbufferDeLectura = New Byte(100) {}
While True
'Se queda esperando a que llegue algĂșn mensaje.
Vstm.Read(VbufferDeLectura, 0, VbufferDeLectura.Length)
'Se evalĂșa que llega en la cabecera del mensaje.
Me.Inter.interpretar(Encoding.ASCII.GetString(VbufferDeLectura))
End While
End Sub
Here it is the class interprete, that will try to understand the string.
Public Class Interprete
Property Codigo As String
Property Cotizacion As Integer
Property Cabecera As String
Private VAcciones As DataTable
Public Property Acciones() As DataTable
Get
Return VAcciones
End Get
Set(ByVal value As DataTable)
VAcciones = value
End Set
End Property
Public Sub interpretar(Data As String)
Me.Cabecera = Nothing
Me.Codigo = Nothing
Dim buff() As String = Split(Data, "!!")
Dim arr() As String = Split(buff(0), "||")
Me.Cabecera = arr(0)
Me.Codigo = arr(1)
Select Case Cabecera
Case "COT"
Cotizaciones(arr)
End Select
End Sub
Public Sub Cotizaciones(M As String())
Dim DR As DataRow = Acciones.NewRow
Dim buffer(3) As Object
buffer(0) = ""
buffer(1) = 0
buffer(2) = M(1)
buffer(3) = M(2)
DR.ItemArray = buffer
Acciones.Rows.Add(DR)
End Sub
End Class
How can i use the datagridview safely?
Also can you guys recomend any books for vb?
You should invoke that data table action on the GUI thread:
Me.BeginInvoke(New Action(Sub()
Dim DR As DataRow = Acciones.NewRow
Dim buffer(3) As Object
buffer(0) = ""
buffer(1) = 0
buffer(2) = M(1)
buffer(3) = M(2)
DR.ItemArray = buffer
Acciones.Rows.Add(DR)
End Sub))

Get Selected Item From Combobox

I have a combobox with items from a DataTable, the ff executes when the form loads:
dbConnection = New SqlCeConnection("Data Source=Journal.sdf")
dbDataAdapter = New SqlCeDataAdapter("SELECT * FROM setting_unit", dbConnection)
dbDataAdapter.Fill(dbTable)
cbxSettingsUnit.DataSource = New BindingSource(dbTable, Nothing)
cbxSettingsUnit.DisplayMember = "name"
cbxSettingsUnit.ValueMember = "name"
The method when there is a changed in the combox box:
Private Sub cbxSettingsUnit_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbxSettingsUnit.SelectedIndexChanged
tempString = cbxSettingsBusinessUnit.Items(cbxSettingsBusinessUnit.SelectedItem).ToString
MessageBox.Show(tempString)
End Sub
there is an error at the line:
tempString = cbxSettingsBusinessUnit.Items(cbxSettingsBusinessUnit.SelectedItem).ToString
How do I get the selected item from the combox box?
Most of the .net "listing-controls" who have a DataSource property search for the implementation of the IListSource. So if you set a DataTable as datasource, you're actually setting the DataTable.DefaultView as the datasource.
Me.ComboBox1.DataSource = myDataTabele
Equals
Me.ComboBox1.DataSource = myDataTabele.DefaultView
So now you have a ComboBox packed with items of type DataRowView.
Dim selectedRowView As DataRowView = DirectCast(Me.ComboBox1.SelectedItem, DataRowView)
Dim selectedDisplayMemberValue As String = Me.ComboBox1.SelectedText
Dim selectValueMemberValue As Object = Me.ComboBox1.SelectedValue
And this is how you should do it:
Private Sub cbxSettingsUnit_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbxSettingsUnit.SelectedIndexChanged
Dim item As DataRowView = TryCast(Me.cbxSettingsUnit.SelectedItem, DataRowView)
If (Not item Is Nothing) Then
With item.Row
'You have now access to the row of your table.
Dim columnValue1 As String = .Item("MyColumnName1").ToString()
Dim columnValue2 As String = .Item("MyColumnName2").ToString()
End With
End If
End Sub
So why did you get an error? Yes, you are trying to cast a DataRowView to an Integer.
' |
tempString = cbxSettingsBusinessUnit.Items(cbxSettingsBusinessUnit.SelectedItem).ToString
Try this:
Dim row_v As DataRowView = comboBox1.SelectedItem
Dim row As DataRow = row_v.Row
Dim itemName As String = row(0).ToString()
You have to use this
tempString = cbxSettingsUnit.Items(cbxSettingsUnit.SelectedIndex).ToString
try using below code
Try
DS = New DataSet
Tabel = "SELECT * FROM setting_unit"
Dim CB As New OleDb.OleDbDataAdapter(Tabel, dbConnection)
CB.Fill(DS, "setting_unit")
'
Me.cbxSettingsUnit.DataSource = Prf.Tables(0)
Me.cbxSettingsUnit.ValueMember = "name"
Me.cbxSettingsUnit.DisplayMember = "name"
Catch ex As Exception
End Try
try this:
combo.datasource = datatable
combo.displaymember = "abbreviation"
combo.valuemember = "abbreviation"
then getting the selected item use this:
on SelectionChangeCommitted event of combo box put this:
tmpString=combo.selectedvalue
msgBox(tmpString)