Open Form faster & remove "System.Data.DataRowView" flicker from Combobox data binding - vb.net

I have plenty Comboboxes on my form (around 20), and all of them are displaying items from different tables of my DB. If I put all code on Form_Load event then Form opens very slow. So I tried to paste code in different varieties, and currently I'm stuck at Combobox_Enter event - now Form loads fast, but when I click on drop-down of combobox I see sometimes "System.Data.DataRowView" flickering before items are loaded in Combobox. Is there any way to achieve both - fast Form opening & Combobox loading Items without flickering ?....So far I tested with Form_Activate,Form_GotFocus(not working) and Combobox_GotFocus,Combobox_MouseHover,Combobox_Click(not exactly perfect). This is an example of how I bind my Comboboxes:
Private Sub Combobox1_Enter(sender As Object, e As EventArgs) Handles Combobox1.Enter
Dim SQL As String = "SELECT Name from MyTable"
Dim dtb As New DataTable()
Using con As OracleConnection = New OracleConnection("Data Source=MyDB;User Id=Lucky;Password=MyPassword;")
Try
con.Open()
Using dad As New OracleDataAdapter(SQL, con)
dad.Fill(dtb)
End Using
Combobox1.DataSource = dtb
Combobox1.DisplayMember = "Name"
con.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
con.Dispose()
End Try
Combobox1.SelectedIndex = -1
End Using
End Sub
I also tried with declaring " Public con As OracleConnection", but output is same as I have It now.
Any help appreaciated !

When binding a ComboBox or the like, you should pretty much ALWAYS set the DataSource last. You are not and that's why you see "System.Data.DataRowView" displayed.
When you bind a list to a ComboBox, the control will display data from the column or property specified in the DisplayMember if there is one, otherwise it will call ToString on each item. In your code, you first set the DataSource and, at that point, the DisplayMember is not set so the control calls ToString on each item. The result of that is "System.Data.DataRowView". When you then set the DisplayMember, those values that the control just went to the trouble of generating and displaying are discarded and the DisplayMember is used to get new values.
Even if you weren't seeing that effect, you'd still be wasting your control's time generating values that you don't want. ALWAYS set the DisplayMember, ValueMember or the like before setting the DataSource in code unless you have a specific reason not to. The only reason that I'm aware of is when you're binding a CheckedListBox, which has an issue when DataSource is set last.
By the way, shouldn't you have a test there to only retrieve data if there is no data already loaded? You don't want to reload data if the user returns to the same control, do you?

Related

DataGridView does not update after delete, update or insert

I have a DatagGridView which has a DataSet from an Access database. I have a problem when I delete, update or insert data.
This is an example from my update method.
Private Sub btnactualizar_Click(sender As Object, e As EventArgs) Handles btnactualizar.Click
novacios()
Try
con = New OleDb.OleDbConnection(ruta)
con.Open()
Dim actualiza As String = "UPDATE Usuarios SET nombre_real=#a1, correo = #a2, pass = #a3, activo = #a4 WHERE Correo = #a5"
sentencia = New OleDb.OleDbCommand(actualiza)
sentencia.Connection = con
sentencia.Parameters.AddWithValue("#a1", txtusuarios.Text)
sentencia.Parameters.AddWithValue("#a2", txtmail.Text)
sentencia.Parameters.AddWithValue("#a3", txtpass.Text)
sentencia.Parameters.AddWithValue("#a4", txtactivo.Text)
sentencia.Parameters.AddWithValue("#a5", txtusuarios.Text)
sentencia.ExecuteReader()
con.Close()
MessageBox.Show("Actualización realzada con éxito", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Information)
Me.UsuariosTableAdapter.Fill(Me.Bd_proyectoNDataSet.Usuarios)
limpiatextos()
Catch ex As Exception
ex.Message.ToString()
End Try
End Sub
As we can see after the messagebox, the list should be updated with the fill method. But the datagrid is still the same.
Here some pictures to understand what I'm talking about. I will appreciate any help.
Before updating the data
After updating the data. Nothing happened
You're doing things backwards. Don't make a change to the database and then try to update the grid from there. You update the local data first and then save that change to the database.
Your grid is bound to a BindingSource and that is bound to a DataTable in your typed DataSet. That's where you should be making the change. It may be that you should be binding your TextBoxes to the same data, in which case the modifications to the data would happen automatically. If not then you should be copying the data from the TextBoxes back into the typed DataRow you're editing. That grid will automatically reflect that change. YOu then call Update on your table adapter to save those changes from the DataTable back to the database.
In short, don't make changes directly to the database and then try to pull those changes from the database into your local data. Make the changes to the local data first, then save those changes to the database.

How to run code in real time across multiple tabs, windows form, vb.net

I am currently programming in vb.net for a windows forms applications.
I have a windows form with multiple tabs and within each tab I have a DGV. Each DGV is connected to an sql server table, the same table across all tabs.
I want to use a check box to copy rows of data from the sql table to a specific tab. In this case I want to try and have this happen in real time, so without using a "refresh" button or something like that.
On each row in every tab I want the row of data to appear or disappear from the last tab depending on the status of the check box.
I have attached code and a picture. The code is used on the form load event to load the tables into the tabs. In the image you can see i want the rows to be loaded into the "ordered floors" tab after the check box has been checked.
Private Sub FormOrdered_Load(sender As Object, e As EventArgs) Handles Me.Load
'load line 2 tab
Try
Using conn1 As New SqlConnection(connstring)
conn1.Open()
Using comm1 As SqlCommand = New SqlCommand("Select LineNumber, ShearNumber, JobNumber, FloorNumber, OrderedBy, DateOrdered, Ordered FROM Production.dbo.tblFCordered where LineNumber = 2", conn1)
Dim da As New SqlDataAdapter
da.SelectCommand = comm1
da.Fill(Line2)
End Using
conn1.Close()
End Using
DataGridLine2.DataSource = Line2
Catch ex As Exception
MsgBox("Unable to make SQL Connection to load Line 2 Table, please contact an engineer!")
MsgBox(ex.ToString)
End Try
image
You could just clone the rows from the DGV when you check the checkbox and add them to the Ordered floors dgv.
Something like:
Private Sub CopyRows_CheckedChanged() Handles CopyRows.CheckedChanged
For each r as DataGridViewRow in MyDGV.Rows
dgvOrderedFloors.Rows.Add(r.Clone())
next
End Sub
You'll have to modify this to suit obviously, but I think something along these lines should do what you want.
Or you could clone the data tables you use for each datagridview, and add them to one master table which will be the datasource for your Ordered floors datagridview.
That would be better, but might be more work upfront.

Faux Databinding a Recordset to a Datagridview

I am updating a very old vb6 program that includes recordsets bound to an old third party grid control. The recordset functionality is so ingrained into the program that it is not an option to replace them. So, I replaced the unfunctional grid with a datagridview and I fill it using a dataadapter and a dataset. The problem is that the recordset was originally bound to the grid and using a dgv breaks the binding.
So this is what I am trying to do. I have a function that passes in the old recordset and the new dgv, and fills it. I would like to create a dynamic handler to the dgv's selectionchanged event to update the rs with the current position on the dgv (rs.aboluteposition = dgv.row), thus updating the rs cursor to the current position in the dgv, making a sort of faux data binding.
Something like this....
AddHandler dgv.SelectionChanged, AddressOf RefreshRecordset
Public Sub RefreshRecordset()
myRS.AbsolutePosition = dgv.Row
End Sub
A couple things though. I have to track if the event handler was already created, and the associated recordset that goes with this specific datagridview. Also, since this is a global function to update many dgvs with many rs, it needs to have a way to track the recordset. I was thinking of somehow using the tag of dgv? Maybe create a dictionary of all the recordsets then look it up by the name of the dgv?
Below is my original method that worked pretty well. I eventually refined it and put it in a class for each recordset. I also updated it to accept true dbgrids. By wrapping it in a class, I was able to remove the dictionaries. In the New function, I pass in either grid and a recordset. From there, I set up event handlers to handle both the grid row change and also the recordset MoveComplete event. I had to use the MoveComplete because the RecordsetChangeComplete has a bug and doesn't always fire correctly. I just check in the MoveComplete if the record count had changed. If so, refresh the grid. Lastly, I added a removehandler for each of the events in the finalize function.
////// The Original Answer //////
For instance, like this... (I CAN'T believe this worked...)
Public dict as new Dictionary(Of String, ADODB.Recordset)
Public Sub FillGrid(ByRef dgv as DataGridView, ByRef rs as ADODB.RecordSet)
'.... Fill the grid with the tableadapter, blah blah.
If Not dict.ContainsValue(rs) Then
dict.add(dgv.Name, rs)
AddHandler dgv.SelectionChanged, AddressOf RefreshRecordset)
' To make the event fire correctly, I think
dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect
End if
End Sub
Public Sub RefreshRecordset(sender As Object, e As System.EventArgs)
Dim dgv as DataGridView = Ctype(sender, DataGridView)
If dict.ContainsKey(dgv.Name) then
Dim rs as ADODB.Recordset = dict(dgv.Name)
rs.AbsolutePosition = dgv.CurrentCell.RowIndex
End if
End Sub
Now I need to create a handler to the recordset to refresh the dgv everytime the recordset is updated.
And btw, I know there are probably other ways to do this and I would absolutely would love to hear them! Please feel free!
Thanks!

combobox text still showing previous value on change

I am using 1 combobox to populate a 2nd combobox. What is happening however, is that the 2nd combobox dropdown is changing and displaying the correct values but when the change occurs, the text property still retains the old value. I am using items.clear() and thought that would also clear the text value of the combobox.
I am using winforms and would be grateful if someone could point out my newbie error. Thanks
Private Sub cmbCustomer_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmbCustomer.SelectedIndexChanged
' This is the routine to populate the departments box with values from customer
sql = "SELECT * from Departments WHERE Customer = ?"
Dim cmd As New OleDb.OleDbCommand
cmd.Parameters.AddWithValue("#p1", cmbCustomer.Text)
cmd.CommandText = sql
cmd.Connection = oledbCnn
dr = cmd.ExecuteReader
cmbDept.Items.Clear()
cmbRequestBy.Items.Clear()
While dr.Read()
cmbDept.Items.Add(dr("Name"))
End While
cmd.Dispose()
dr.Close()
'oledbCnn.Close()
End Sub
You are clearing the Items collection not the Text property of the combo.
This behavior depends on the DropDownStyle property of the combobox.
The default is DropDown that allow the combo to maintain separate inner controls for Items (A List of some kind) and Text (a TextBox)
If you change the property to DropDownList clearing the Items collection will clear also the 'text' part of it.
Of course you loose the possibility to type inside the TextBox portion of the combobox for example to add an item not included in the list
See Microsoft Connect for Microsoft Response to similar question

vb.net Bind a combobox to a datasource

Over the past few days, I've read about a thousand forum posts, and looked at many code samples, but I still can't figure this out.
My goal is to populate a combobox with values from an Access 2007 query. I can do this by using the DataSource, DisplayMember and ValueMember properties, but regardless of the data in the query, the comboboxes all just default to the to first item in the items collection and don't change when the main BindingSource is moved. I am binding the controls with this line of code:
ComboBox1.DataSource = DataSet1.qryItemSourceTest
ComboBox1.DisplayMember = "SourceTestDisplayField"
ComboBox1.ValueMember = "SourceTestIDField"
Combobox1.DataBindings.Add(New Binding("SelectedValue", qryTestBindingSource, "TestField", True))
I have also tried using a BindingSource as a DataSource.
I have also tried using an array as a DataSource.
If I drag the control on from the Data Source tab in the IDE, it will scroll through records properly, but it will only display the value and not the query 'look-up' value that I want the combobox to display. I have tried changing the DisplayMember and ValueMember properties of the combobox after dragging it on from the Data Sources tab and that seems to break the functionality as well.
I'm looking for some best practices here. I know I'm missing something easy here and I apologize for post an issue that has already been covered so many times, but I could use some individual help here.
Edit: I eventually was able to accomplish my goal using the Visual Studio IDE Properties window. The second property on a control is a Data Bindings property which expands into exactly what I needed. I just never saw this before because it was not in alphabetically order like everything else.
Hi you can do this code to populate data into combo
Try
Dim cn As New OleDbConnection
cn.ConnectionString = conString
cn.Open()
cmd.Connection = cn
cmd.CommandText = "your query"
'Execte reader function is used to hold more than one value from the table
dr = cmd.ExecuteReader()
' Fill a combo box with the datareader
Do While dr.Read = True
ComboBox1 = dr.Item(0)
Loop
cn.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
If you have any more problems don't hesitate to ask.