I'm trying to refresh datagridview after adding multiple records which were added programmatically, using bindingsource and datasource. My code:
Private Async Function RefreshData() As Task
Await Task.Delay(15000)
bs.EndEdit()
daProducts.Update(dtProducts)
DataGridView1.DataSource = Nothing
DataGridView1.DataSource = bs 'Insert your DataSource here
bs.ResetBindings(False)
...
When I call this function on form load event, it can't display any records.
Another thing is I get error if I don't use async function (because of setting DefaultCellStyle.Alignment).
My formload event: http://sudrap.org/paste/text/554747/
This might be helpful for you:
Private Sub updatedgv()
Dim conn As New MySqlConnection(My.Settings.myConn)
Dim da As New MySqlDataAdapter
Dim ds As New DataSet
Dim str1 As String = "select * from tableName"
da.SelectCommand = New MySqlCommand(str1, conn)
da.Fill(ds)
conn.Close()
ProductDataGridView.DataSource = ds.Tables(0)
End Sub
the explanation can be found in the link
http://www.codeproject.com/Questions/372731/how-to-refresh-datagridview-in-vb-net
Related
I am using Visual Studio, web forms, and vb.net. Why is my list count 0 outside of PopulateNames()?
I have a list at the top of my vb.net code:
Private defaultNames As List(Of ListItem) = New List(Of ListItem)()
I can add items to my list here:
'Populate cbNames with all names
Private Sub PopulateNames()
Using sqlConn As New SqlConnection(ConfigurationManager.ConnectionStrings("databasehere").ConnectionString)
sqlConn.Open()
Using sqlCmd As New SqlCommand()
sqlCmd.CommandText = "select [ID], [FirstName] from vwNames"
sqlCmd.Connection = sqlConn
Using sdr As SqlDataReader = sqlCmd.ExecuteReader()
While sdr.Read()
Dim item As New ListItem()
item.Text = sdr("FirstName").ToString()
item.Value = sdr("ID").ToString()
'Add name from database into checkboxlist
cbNames.Items.Add(item)
'Add item from checkboxlist cbNames into list defaultNames
defaultNames.Add(item)
End While
End Using
End Using
End Sub
defaultNames is count of 6 in PopulateNames() but count of 0 anywhere else. Why won't my list items save into my defaultNames list?
You need to read up on scope.
Private defaultNames As List(Of ListItem) = New List(Of ListItem)()
Is scoped to an instance of a class, and is initialized with a new list whenever the containing class is instantiated. For a form, that will most likely be whenever it is shown.
Even if you do want that private member and don’t want to expose it elsewhere, populating it the way you do is simply bad.
It should either be a parameter that gets filled, or it should be the result of a function, or the data reader should be returned and used to populate the list, or there should be a function passed in as a parameter that does something with it.
Also, although it entails more work, you probably shouldn’t be using a list item (a GUI class) whether this is a web form or winform applications. Which is why I prefer the last 2 option’s and think the last is generally best if you are going to do something with it yourself as opposed to passing it off to something else:
Private sub init()
PopulateNames(Sub(dr as IDataReader)
Dim item As New ListItem()
item.Text = dr("FirstName").ToString()
item.Value = dr("ID").ToString()
'Add name from database into checkboxlist
cbNames.Items.Add(item)
'Add item from checkboxlist cbNames into list defaultNames
defaultNames.Add(item)
End sub
End Sub
Private Sub PopulateNames(loader as Action(Of IDataReader))
Using sqlConn As New SqlConnection(ConfigurationManager.ConnectionStrings("databasehere").ConnectionString)
sqlConn.Open()
Using sqlCmd As New SqlCommand()
sqlCmd.CommandText = "select [ID], [FirstName] from vwNames"
sqlCmd.Connection = sqlConn
Using sdr As SqlDataReader = sqlCmd.ExecuteReader()
While sdr.Read()
loader(sdr)
End While
End Using
End Using
End Sub
Given this structure, if you make the PopulateNames method public, it can be used in multiple different ways. You are no longer limited to creating a list of ListItems, as all of the actual work is done in the lambda (or if you prefer in a separate function).
Assumption: This is a Winforms application.
Don't open the connection until directly before the .Execut.... To save a few indents, you can combine the connection Using and the command Using with a comma at the end of the connection Using. You can pass the CommandText and the Connection directly to the constructor of the Command.
You don't want to fill lists and, definitely, you don't want to update the user interface (comparatively, a very slow process) while the connection is open. Readers require an open connection. Just fill a DataTable and shut down the database objects.
To fill the CheckedListBox just set the DisplayMember, ValueMember and DataSource.
Private Sub PopulateNames()
Dim dt As New DataTable
Using sqlConn As New SqlConnection(ConfigurationManager.ConnectionStrings("databasehere").ConnectionString),
sqlCmd As New SqlCommand("select [ID], [FirstName] from vwNames", sqlConn)
sqlConn.Open()
Using sdr As SqlDataReader = sqlCmd.ExecuteReader()
dt.Load(sdr)
End Using
End Using
cbNames.DisplayMember = "FirstName"
cbNames.ValueMember = "ID"
cbNames.DataSource = dt
End Sub
ListItem is not a type available without a reference and Imports to a special library.
For a web application
Private Sub PopulateNames()
Dim dt As New DataTable
Using sqlConn As New SqlConnection(ConfigurationManager.ConnectionStrings("databasehere").ConnectionString),
sqlCmd As New SqlCommand("select [ID], [FirstName] from vwNames", sqlConn)
sqlConn.Open()
Using sdr As SqlDataReader = sqlCmd.ExecuteReader()
dt.Load(sdr)
End Using
End Using
cbNames.DataSource = dt
cbNames.DataTextField = "FirstName"
cbNames.DataValueField = "ID"
cbNames.DataBind()
End Sub
To access the DataTable you can either make a class level variable or create a Function and return the DataTable
Private Function GetNameData() As DataTable
Dim dt As New DataTable
Using sqlConn As New SqlConnection(ConfigurationManager.ConnectionStrings("databasehere").ConnectionString),
sqlCmd As New SqlCommand("select [ID], [FirstName] from vwNames", sqlConn)
sqlConn.Open()
Using sdr As SqlDataReader = sqlCmd.ExecuteReader()
dt.Load(sdr)
End Using
End Using
Return dt
End Function
Protected Sub Button1_Click(ByVal sender As Object, e As System.EventArgs) Handles Button1.Click
Dim dt = GetNameData()
cbNames.DataSource = dt
cbNames.DataTextField = "FirstName"
cbNames.DataValueField = "ID"
cbNames.DataBind()
End Sub
Currently, my code is like this:
Private Sub btnAlaCarte_Click(sender As Object, e As EventArgs) Handles btnAlaCarte.Click
Dim item(2) As String
Dim description(2) As String
Dim price(2) As String
conn.Open()
sql = "SELECT name, description, price FROM Food WHERE id LIKE 'F%';"
cmd = New SqlCommand(sql, conn)
dr = cmd.ExecuteReader
If dr.HasRows Then
For count = 1 To 3 Step 1
dr.Read()
lklblItem1.Text = dr.GetValue(dr.GetOrdinal("name"))
lblDescription.Text = dr.GetValue(dr.GetOrdinal("description"))
lblPrice.Text = dr.GetValue(dr.GetOrdinal("price"))
Next
End If
dr.Close()
conn.Close()
End Sub
I have 3 set of label in my design. Each of the set consist of 1 linklabelItem, 1 labelDescription and 1 labelPrice. All of them will display different output from database. I manage to extract all of the data that i want. But now the problem is the FOR....NEXT loop only display the output at the first set.
Is there any possibility for me to use For....NEXT Loop to achieve my concept?
Hopes my question is clear enough.
In your case DataGridView control will do the job without explicit For .. Next loop.
' Create a class to represent a food item
Public Class AlaCarteItem
Public Property Name As String
Public Property Description As String
Public Property Price As Decimal
End Class
' Extract loading data into dedicated function with properly disposed sql connection
Private Function GetAlaCarte() As List(Of AlaCarteItem)
Dim query As String = "SELECT name, description, price FROM Food WHERE id LIKE 'F%';"
Using connection As New SqlConnection(connectionString)
Using command As New SqlCommand(query, connection)
connection.Open()
Dim items = new List(Of AlaCarteItem)()
Using reader AS SqlDataReader = command.ExecuteReader()
While reader.Read()
Dim item As New AlaCarteItem With
{
.Name = reader.GetString(0),
.Description = reader.GetString(1),
.Price = reader.GetDecimal(2),
}
items.Add(item)
End While
End Using
Return items
End Using
End Using
End Function
Add DataGridView control to the form
Private btnAlaCarte_Click(sender As Object, e As EventArgs) Handles btnAlaCarte.Click
Me.DataGridView.DataSource = GetAlaCarte()
' Make all columns read only
For Each column As DataGridViewColumn in Me.DataGridView.Columns
column.ReadOnly = True
End With
End Sub
You can create DataGridView with predefined columns and make them readonly in design time, then you don't need to do this in the code.
Start in the form designer.
In the toolbox drag a BindingNavigator to the form. Reference https://learn.microsoft.com/en-us/dotnet/framework/winforms/controls/bindingnavigator-control-overview-windows-forms
Remove the buttons that you will not use by right clicking on the buttons and selecting delete. You will end up with a strip that looks like this.
Then, in the code
Fill a DataTable
Create a BindingSource
Set the DataSource of the BindingSource to the DataTable
Finally set the BindingSource property of the BindingNavigator control to the the BindingSource.
Next your will add DataBindings to each of your controls.
The .Add method takes 3 parameters in this overload.
1.The property to bind to, in this case we are binding the Text property
2. The BindingSource (bindSrc)
3. The member of the DataTable to bind to.
Note: The name of my Form is BindingNavigator
Private Sub BindingNavigator_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt = LoadData()
Dim bindSrc As New BindingSource
bindSrc.DataSource = dt
BindingNavigator1.BindingSource = bindSrc
lblItem.DataBindings.Add(New Binding("Text", bindSrc, "name"))
lblDescription.DataBindings.Add(New Binding("Text", bindSrc, "description"))
lblPrice.DataBindings.Add(New Binding("Text", bindSrc, "price"))
End Sub
Private Function LoadData() As DataTable
Dim dt As New DataTable
Using conn As New SqlConnection("Your connection string"),
cmd As New SqlCommand("SELECT name, description, price FROM Food WHERE id LIKE 'F%';", conn)
conn.Open()
dt.Load(cmd.ExecuteReader)
End Using
Return dt
End Function
You will then be able to move through the records with the BindingNavigator toolbar.
You are replacing your labels' texts in each iteration. I recommend to use a datagrid instead. However, if you want to use labels anyway, update your loop as this:
lklblItem1.Text += vbNewLine + dr.GetValue(dr.GetOrdinal("name"))
lblDescription.Text += vbNewLine + dr.GetValue(dr.GetOrdinal("description"))
lblPrice.Text += vbNewLine + dr.GetValue(dr.GetOrdinal("price"))
I am trying to fill a datagrid with data from access, but every time I run this program i get an error saying ConnectionString property has not been initialized i have tried everything i know. Can someone please help
Private Sub RefreshData()
cnn = New OleDb.OleDbConnection
cnn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\My_db.accdb"
If Not cnn.State = ConnectionState.Open Then
' open connection '
cnn.Open()
End If
Dim da As New OleDb.OleDbDataAdapter()
Dim dt As New DataTable
'fill datatable'
da.Fill(dt)
Me.DataGridView1.DataSource = dt
' close connection'
cnn.Close()
End Sub
Private Sub BindGrid()
If Not cnn.State = ConnectionState.Open Then
' open connection '
cnn.Open()
End If
Dim cmd As New OleDb.OleDbCommand
cmd.Connection = cnn
cmd.CommandText = "SELECT * FROM Training log WHERE Runner Name='" & Profile.UsernameTextBox.Text & "'"
cmd.ExecuteNonQuery()
Me.RefreshData()
cnn.Close()
End Sub
It looks like the OleDbCommand is never set to use the OleDbConnection object, and the DataAdapter is never set to use the command. Try this, which also fixes several other items that do not conform to commonly accepted practice:
'Put this module in a separate file
'Any and *ALL* code that talks directly to the DB should go in this module, and use the style of the RefreshData() method below.
Public Module DataLayer
Private Property ConnectionString() As String
Get
Return "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\My_db.accdb"
End Get
End Property
'I left the name alone so you could match it up to your original code,
' but a better name would be something like "TrainingLogByRunner()"
Public Function RefreshData(ByVal RunnerName As String) As DataTable
Dim dt As New DataTable
Using cnn As New OleDb.OleDbConnection(ConnectionString), _
cmd As New OleDb.OleDbCommand("SELECT * FROM [Training log] WHERE [Runner Name]= ?", cnn), _
da As new OleDb.OleDbDataAdapter(cmd)
'**NEVER** use string concatentation to substitute this kind of value into a query!
'Had to guess at column type/length here
cmd.Parameters.Add("?", OleDbType.VarWChar, 40).Value = RunnerName
'No need to call Open() for the connection...
' the DataAdapter.Fill() method will manage opening/closing the connection
da.Fill(dt)
End Using
Return dt
End Function
End Module
Private Sub BindGrid()
Me.DataGridView1.DataSource = DataLayer.RefreshData(Profile.UsernameTextBox.Text)
End Sub
I am trying to write a function that queries the sqlite db I have. For some reason it does not work properly. Below are the supporting functions that I am using. I can get it to add tables perfectly fine.
Private Sub GetSqlConnection()
Me.SQLConnectionString = New SQLiteConnectionStringBuilder
Me.SQLConnectionString.DataSource = Path.Combine(Application.StartupPath, "mydb.sqlite")
Me.SQLConnectionString.Version = 3
SQLConnection = New SQLiteConnection(Me.SQLConnectionString.ConnectionString)
End Sub
Private Sub Query(ByVal SQLString As String)
Try
Dim SQLiteDRObj As SQLiteDataReader
Dim ResultsTableObj As DataTable = Nothing
Dim ResultSet As DataSet = Nothing
Dim SQLAdapter As SQLiteDataAdapter = Nothing
Me.GetSqlConnection()
SQLConnection.Open()
SQLCommand = New SQLiteCommand(SQLConnection)
SQLCommand.CommandText = SQLString
SQLiteDRObj = SQLCommand.ExecuteReader()
ResultsTableObj.Load(SQLiteDRObj)
SQLiteDRObj.Close()
SQLConnection.Close()
SQLConnection.Dispose()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
object shows as filled http://josephberardi.com/stackoverflow/objfilled.png
object shows as filled http://josephberardi.com/stackoverflow/exception.png
ResultsTableObj is Nothing when you call the Load method
Change this line to
Private Sub Query(ByVal SQLString As String)
Try
....
Dim ResultsTableObj As DataTable = New DataTable()
....
I have a bit of code which loads data from a stored procedure in MS SQL Server and then loads the data into a DataGridView, which works fine. What I want is for the code that connects / loads the data to sit in my Database class and then everything associated with the DataGridView to be stored in my Form but I am having problems passing the contents of the BindingSource over to the Form from the Database class.
Form1 code:
Public Class Form1
Dim myDatabaseObj As New Class1()
Dim bindingSource1 As New BindingSource()
Dim connectString As New SqlConnection
Dim objDataAdapter As New SqlDataAdapter
Dim table As New DataTable()
Dim tabletest As New DataTable()
Private Sub loadCompanyList()
Try
Me.dgv_CompanyList.DataSource = Me.bindingSource1
getCompanyList()
Catch ex As NullReferenceException
End Try
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
loadCompanyList()
End Sub
End Class
When I try place the getCompanyList() in a class and then create a new object that references the Form() it does not seem to return any value from the table to the MyForm.BindingSource1.Datasource meaning my DataGridView displays no data.
Database class code:
.....
Private Sub getCompanyList()
Try
Dim myForm as new Form()
connect_Transaction_Database()
objDataAdapter.SelectCommand = New SqlCommand()
objDataAdapter.SelectCommand.Connection = connectString
objDataAdapter.SelectCommand.CommandText = "sp_GetCompanyList"
objDataAdapter.SelectCommand.CommandType = CommandType.StoredProcedure
Dim commandBuilder As New SqlCommandBuilder(Me.objDataAdapter)
Dim table As New DataTable()
table.Locale = System.Globalization.CultureInfo.InvariantCulture
Me.objDataAdapter.Fill(table)
**MyForm.bindingSource1.DataSource = table**
Catch ex As DataException
MsgBox(ex.Message)
Catch ex As NullReferenceException
MsgBox(ex.Message)
End Try
disconnect_Transaction_Database()
End Sub
This question has just been bumped by the Community user so I thought I would provide an answer which may help others in the future.
Firstly, I would consider implementing Using:
Managed resources are disposed of by the .NET Framework garbage collector (GC) without any extra coding on your part. You do not need a Using block for managed resources. However, you can still use a Using block to force the disposal of a managed resource instead of waiting for the garbage collector.
Secondly, you don't need to use a SqlDataAdapter. Instead you can load a DataTable using the SqlCommand class and return that. I would also contain the SqlConnection in the method rather than having it opened and closed in a different one.
Your code would look something like this:
Form1 code:
Public Class Form1
Private Sub loadCompanyList()
Dim myDatabase As New Database
Me.dgv_CompanyList.DataSource = myDatabase.getCompanyList()
End Sub
End Class
Database code:
Public Class Database
Public Function getCompanyList() As DataTable
Dim dt As New DataTable
Using con As New SqlConnection(connectionString),
cmd As New SqlCommand("sp_GetCompanyList", con) With {.CommandType = CommandType.StoredProcedure}
con.Open()
dt.Load(cmd.ExecuteReader())
End Using
Return dt
End Function
End Class
You want getCompanyList to be a function, which returns a DataTable. Then, forget the BindingSource (if the DataGridView is read-only) and set the DataSource property to the function:
Me.dgv_CompanyList.DataSource = getCompanyList
I would suggest you make the GetCompanyList method into a Function that returns the DataTable filled by the SqlDataAdapter. There's no real reason this Sub should have a dependency on the form. Instead a method in the form could call this to get the DataTable and then perform the binding.
Public Function GetCompanyList() As DataTable
...
...
Dim table As New DataTable()
table.Locale = System.Globalization.CultureInfo.InvariantCulture
Me.objDataAdapter.Fill(table)
Return table
...
...