ifselectedindex changed , show data in a textbox - vb.net

I've linked an access database to my form.
I have 1 table , 2 rows
1 = Researchtype short text
2 = Researchdetails (long text)
In my combobox1 i've binded my researchtype row so i can choose a type of research.
Question now: how can i bind the details data to the richtextbox below it in order to show the research data as soon as i choose a research type?
I've tried if else combos, try catch combos,
i'm thinking i'm actually overthinking the issue here.
What would be the easiest way to "select from dropdown" and show the result in textbox.
I'm a vb.net beginner
Public Class Onderzoeken
Private Sub Onderzoeken_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'PatientenDatabaseDataSetX.tbl_OnderzoeksTypes' table. You can move, or remove it, as needed.
Me.Tbl_OnderzoeksTypesTableAdapter.Fill(Me.PatientenDatabaseDataSetX.tbl_OnderzoeksTypes)
End Sub
Private Sub cboxOnderzoek_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboxOnderzoek.SelectedIndexChanged
If cboxOnderzoek.SelectedItem = Nothing Then
cboxOnderzoek.Text = ""
Else
rtbBeschrijvingOnderzoek.Text = CStr(CType(cboxOnderzoek.SelectedItem, DataRowView)("OZ_Onderzoeksbeschrijving"))
End If
End Sub
End Class
I added the entire code of that page now , it's not much, but as stated: I added the binding source and displaymember "researchtype" to the combobox.
So when i start the form, i can choose a type of research.
Now i need to show the description of the research in the richtextbox

In the Form.Load...
I have a function that returns a DataTable that contains columns called Name and Type. I bind the ComboBox to the DataTable and set the DisplayMember to "Name". Each Item in the ComboBox contains the entire DataRowView. I set the TextBox to the first row (dt(0)("Type")) Type column value so the correct information will be displayed for the initial selection.
I put the code to change the textbox display in ComboBox1.SelectionChangeCommitted because the other change events will produce a NRE since .SelectedItem has not yet been set when the form loads. The commited event will only occur when the user makes a selection.
First, cast the SelectedItem to its underlying type, DataRowView. Then you want the value of the Type column. This value is assigned to the text property of the textbox.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt = LoadCoffeeTable()
ComboBox1.DataSource = dt
ComboBox1.DisplayMember = "Name"
TextBox1.Text = dt(0)("Type").ToString
End Sub
Private Sub ComboBox1_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles ComboBox1.SelectionChangeCommitted
TextBox1.Text = DirectCast(ComboBox1.SelectedItem, DataRowView)("Type").ToString
End Sub
Just substitute Researchtype for Name and Researchdetails for Type.

After using 'OleDbDataAdapter' to fill the dataset, you can set 'DisplayMember' and 'ValueMember' for your ComboBox. Every time the index of your ComboBox changes, it's 'ValueMember' will be displayed in richtextbox.
Here's the code you can refer to.
Private dataset As DataSet = New DataSet()
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim connString As String = "your connection String"
Using con As OleDbConnection = New OleDbConnection(connString)
con.Open()
Dim cmd As OleDbCommand = New OleDbCommand()
cmd.Connection = con
cmd.CommandText = "SELECT Researchtype, Researchdetails FROM yourtable"
Dim adpt As OleDbDataAdapter = New OleDbDataAdapter(cmd)
adpt.Fill(dataset)
End Using
ComboBox1.DisplayMember = "Researchtype"
ComboBox1.ValueMember = "Researchdetails"
ComboBox1.DataSource = dataset.Tables(0)
End Sub
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
RichTextBox1.Text = ComboBox1.SelectedValue.ToString()
End Sub
Result of my test.

Related

Checkboxes are keeping myCurrencyManager.AddNew() from working properly

I have a fully functional Windows forms app developed with a read-only datagridview bound to an Access DB.
Databound textboxes are used to edit fields. I then added 3 Checkbox fields to the DB, datagridview and the form. Then added chkName.DataBindings.Add("Checked", DBTable,"Field") just like the Textboxes. The checkboxes work properly displaying the correct data.
Only now when I try to add a row using myCurrencyManager.AddNew() it doesn't work. It does nothing except add a non-accessible row to the end of the datagridview. When I comment out the Checkbox DataBindings lines, everything works properly (without functioning checkboxes).
Any ideas what is wrong?
Here is the code:
Public Class frmRoutes
Dim RoutesConnection As OleDbConnection
Dim JS1Adapter As New OleDbDataAdapter
Dim JS1Table As New DataTable("JOBSITES")
Dim JSBS As BindingSource
Dim JS1State As String = "Edit"
Private Sub frmRoutes_Load(sender As Object, e As EventArgs) Handles MyBase.Load
RoutesConnection = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; Data Source = C:\Microsoft\JS1TestDB.mdb")
RoutesConnection.Open()
Dim JobSitesCommand = New OleDbCommand _
("SELECT REF, STREET, CITY, SPEC, HELPER " +
"FROM Jobsites ORDER BY REF", RoutesConnection)
JS1Adapter.SelectCommand = JobSitesCommand
JS1Adapter.Fill(JS1Table)
JSBS = New BindingSource()
JSBS.DataSource = JS1Table
grdJobSites.DataSource = JSBS
txtRef.DataBindings.Add("Text", JSBS, "REF")
txtStreet.DataBindings.Add("Text", JSBS, "STREET")
txtCity.DataBindings.Add("Text", JSBS, "CITY")
'chkSpecial.DataBindings.Add("Checked", JSBS, "SPEC") 'THESE 2 CHECKBOX DATABINDINGS CAUSE THE 'ADDNEW' METHOD TO FAIL
'chkHelper.DataBindings.Add("Checked", JSBS, "HELPER")
End Sub
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Try
JSBS.AddNew()
Catch ex As Exception
MessageBox.Show("Error Adding a New row.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
JS1State = "Add"
End Sub
Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
JSBS.CancelEdit()
JS1State = "View"
End Sub
End Class
The issue is exactly as I already said: nullable data. I just tested this code (an actual minimal example):
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim table As New DataTable
With table.Columns
.Add("Name", GetType(String))
.Add("Flag", GetType(Boolean))
End With
With table.Rows
.Add("Peter", True)
.Add("Paul", False)
.Add("Mary", True)
End With
BindingSource1.DataSource = table
TextBox1.DataBindings.Add("Text", BindingSource1, "Name")
CheckBox1.DataBindings.Add("Checked", BindingSource1, "Flag")
End Sub
End Class
and an invalid cast exception occurred when adding a new row (via a BindingNavigator) because the Flag column contained DBNull.Value by default and that cannot be cast as type Boolean, which is required for the Checked property. There are two potential solutions. The best one depends on whether you might want to be able save null values or not.
If you don't want to save null values then specify a default Boolean value for that column. That would probably be False but may be True if you want it. That way, when a new row is added, that column already contains a Boolean value that is compatible with the Checked property. In my example, this:
.Add("Flag", GetType(Boolean))
becomes this:
.Add("Flag", GetType(Boolean)).DefaultValue = False
In your case, you'd have to get the appropriate column from the DataTable after populating it and set that property.
Set the ThreeState property of the CheckBox to True, bind to the CheckState property instead of the Checked property and do your own translation between nullable Boolean data in the data source and CheckState values in the control. Making that change to my example might look like this:
Public Class Form1
Private WithEvents checkStateBinding As Binding
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim table As New DataTable
With table.Columns
.Add("Name", GetType(String))
.Add("Flag", GetType(Boolean))
End With
With table.Rows
.Add("Peter", True)
.Add("Paul", False)
.Add("Mary", True)
End With
BindingSource1.DataSource = table
TextBox1.DataBindings.Add("Text", BindingSource1, "Name")
checkStateBinding = New Binding("CheckState", BindingSource1, "Flag")
CheckBox1.DataBindings.Add(checkStateBinding)
End Sub
Private Sub CheckStateBinding_Format(sender As Object, e As ConvertEventArgs) Handles checkStateBinding.Format
'Convert from nullable Boolean to CheckState.
If TryCast(e.Value, DBNull) Is DBNull.Value Then
e.Value = CheckState.Indeterminate
ElseIf CBool(e.Value) Then
e.Value = CheckState.Checked
Else
e.Value = CheckState.Unchecked
End If
End Sub
Private Sub CheckStateBinding_Parse(sender As Object, e As ConvertEventArgs) Handles checkStateBinding.Parse
'Convert from CheckState to nullable Boolean.
Select Case DirectCast(e.Value, CheckState)
Case CheckState.Indeterminate
e.Value = DBNull.Value
Case CheckState.Checked
e.Value = True
Case CheckState.Unchecked
e.Value = False
End Select
End Sub
End Class
The Binding raises its Format event when it needs to get data from the data source for the control and its Parse event when it needs to get data from the control for the data source. If types and/or values don't match up between the two, you can do your own translation.

Indicate combobox values with a specific ids?

I made a Sub that will populate my combobox with loan descriptions. I want to get the loancode of the loandescription on selectedindexchanged without querying again the database. Is this possible? Or should I query the database to get the indicated loancode?
Private Sub LoanProducts()
Using cmd As New SqlClient.SqlCommand("SELECT loancode,loandescription FROM LoanProducts", gSQlConn)
Dim dt As New DataTable
Dim da As New SqlClient.SqlDataAdapter
dt.Clear()
da.SelectCommand = cmd
da.Fill(dt)
For Each row As DataRow In dt.Rows
CmbLoanAvail.Items.Add(row("loandescription"))
Next row
End Using
End Sub
Expected output:
Everytime the combobox index changed, the loancode of the selected loandescription will be displayed to a textbox.
Set DataTable to combobox .DataSource property and populate .ValueMember and .DisplayMember properties with corresponding column names.
Private Sub LoanProducts()
Dim query As String = "SELECT loancode, loandescription FROM LoanProducts"
Using command As New SqlCommand(query, gSQlConn)
Dim data As New DataTable
Dim adapter As New SqlClient.SqlDataAdapter With
{
.SelectCommand = cmd
}
adapter.Fill(data)
CmbLoanAvail.ValueMember = "loancode"
CmbLoanAvail.DisplayMember = "loandescription"
CmbLoanAvail.DataSource = data
End Using
End Sub
You can use SelectionChangeCommitted event to execute some action when user made a selection
Private Sub comboBox1_SelectionChangeCommitted(
ByVal sender As Object, ByVal e As EventArgs) Handles comboBox1.SelectionChangeCommitted
Dim combobox As ComboBox = DirectCast(sender, ComboBox)
Dim selectedCode As String = combobox.SelectedValue.ToString() // returns 'loancode'
End Sub
If you could get DB rows as strongly typed classes, you could make use of ItemSource, DisplayMember and ValueMember, which would solve your problem.
In case you presented, you can use SelectedIndex property of ComboBox. Also, you need to store resultset in some class field (preferably Pirvate one). See example code below:
Public Class Form4
Private _result As DataTable
Private Sub Form4_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt As New DataTable
dt.Columns.Add("col1")
dt.Columns.Add("col2")
dt.Rows.Add("val11", "val12")
dt.Rows.Add("val21", "val22")
' at this point, we got our result from DB
_result = dt
For Each row As DataRow In dt.Rows
ComboBox1.Items.Add(row("col1"))
Next
End Sub
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
Dim selectedIndex = ComboBox1.SelectedIndex
Dim selectedRow = _result(selectedIndex)
End Sub
End Class
Keep your database objects local to the method where they are used so you can ensure that they are closed and disposed. Note the comma at the end of the first Using line. This includes the command in the same Using block.
Set the DataSource, DisplayMember and ValueMember after the Using block so the user interface code doesn't run until the connection is disposed.
To get the loan code you simply access the SelectValue of the ComboBox.
Private Sub LoanProducts()
Dim dt As New DataTable
Using gSqlConn As New SqlConnection("Your connection string"),
cmd As New SqlClient.SqlCommand("SELECT loancode,loandescription FROM LoanProducts", gSqlConn)
gSqlConn.Open()
dt.Load(cmd.ExecuteReader)
End Using
ComboBox1.DataSource = dt
ComboBox1.DisplayMember = "loandescription"
ComboBox1.ValueMember = "loancode"
End Sub
Private Sub ComboBox1_SelectionChangeCommitted(ByVal sender As Object, ByVal e As EventArgs) Handles ComboBox1.SelectionChangeCommitted
MessageBox.Show($"The Loan Code is {ComboBox1.SelectedValue}")
End Sub

SQL Column to TextBox (from ComboBox)

I have managed to add data into a ComboBox from a column out of my SQL table, but I need the rows from across to display in the rest of the textboxes. (I hope I have worded this correctly).
Here is my code currently:
Imports System.Data.SqlClient
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim con As New SqlConnection("Data Source=xxxx;Initial Catalog=ltLeavers;Integrated Security=True")
Dim da As New SqlDataAdapter("SELECT * FROM dbo.mytable", con)
Dim dt As New DataTable
da.Fill(dt)
ComboBox1.DisplayMember = "DISPLAY_NAME"
ComboBox1.DataSource = dt
End Sub
The above works with no issues, all of the items add into the ComboBox but I need the corresponding rows from the other two columns which are EMAIL_ADDRESS and DEPARTMENT to add into TextBoxes from what is selected in the ComboBox.
Under the SelectedIndex_Changed event of the ComboBox; Enter the following code.
Dim dt As New DataTable
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim con As New SqlConnection("Data Source=xxxx;Initial Catalog=ltLeavers;Integrated Security=True")
Dim da As New SqlDataAdapter("SELECT * FROM dbo.mytable", con)
da.Fill(dt)
ComboBox1.DisplayMember = "DISPLAY_NAME"
ComboBox1.DataSource = dt
End Sub
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
Textbox1.Text = CStr(dt.Rows(ComboBox1.SelectedIndex)("EMAIL_ADDRESS"))
Textbox2.Text = CStr(dt.Rows(ComboBox1.SelectedIndex)("DEPARTMENT"))
End Sub
You Will need to declare the data table dt outside your form's load event so it can be visible to the SelectedIndex_Changed event of the combo box.
I suggest you to use BindingSource to get it done.
Try this:
1- Declare your variable type of BindingSource with events. Also, declare your dataset will be used for data.
Dim WithEvents BS As New BindingSource
Dim ds As New DataSet
2- In your Form Load Event, query your data and bind it with both Binding Source and your ComboBox control.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim con As New SqlConnection("Data Source=xxxx;Initial Catalog=ltLeavers;Integrated Security=True")
Dim da As New SqlDataAdapter("SELECT * FROM dbo.mytable", con)
da.Fill(ds, "myPopulatedTable")
ComboBox1.DisplayMember = "id"
ComboBox1.DataSource = ds.Tables("myPopulatedTable")
'Here the new code'
BS.DataSource = ds
BS.DataMember = "myPopulatedTable"
End Sub
3- Add a Sub Procedure to display your data into other text boxes controls.
Private Sub DISPLAYRECORD(Optional ByVal table As String = "myPopulatedTable")
TextBox1.Text = ds.Tables(table).Rows(Me.BS.Position)("column1").ToString
TextBox2.Text = ds.Tables(table).Rows(Me.BS.Position)("column2").ToString()
TextBox2.Text = ds.Tables(table).Rows(Me.BS.Position)("column3").ToString()
End Sub
4- In the PositionChanged event of your Binding Source, call that sub procedure (above)
Private Sub BS_PositionChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles BS.PositionChanged
DISPLAYRECORD()
End Sub
5- Finally, to sync your data with ComboBox selection, you need to change the position of that Binding Source according to the ComboBox index selection
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
BS.Position = ComboBox1.SelectedIndex
End Sub

SqlDataAdapter missing DeleteCommand

I am loading a VB.NET DataGridView using an SqlDataAdapter to fill a DataSet and then setting the DataSource of the DataGridView to the DataSet.
For some reason, the only command that is populated with the SqlCommandBuilder is the SelectCommand. I realize I am only specifying a SELECT query, but I thought the purpose of the SqlCommandBuilder is to generate the Update/Delete/Insert command for me.
The following is the applicable code:
Dim _dstErrorLog As New DataSet
Dim _adapter As SqlDataAdapter
Dim _builder As SqlCommandBuilder
Private Sub ErrorLog_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Call LoadErrorLog()
End Sub
Private Sub LoadErrorLog()
Dim strSql As String
strSql = "SELECT Ident, LogDate, LogDesc FROM dbo.ErrorLog ORDER BY DescDateTime DESC"
_adapter = New SqlDataAdapter(strSql, dataLayer.Connection)
_builder = New SqlCommandBuilder(_adapter)
_adapter.Fill(_dstErrorLog)
grdErrorLog.DataSource = _dstErrorLog.Tables(0)
End Sub
Private Sub grdErrorLog_UserDeletingRow(sender As Object, e As DataGridViewRowCancelEventArgs) Handles grdErrorLog.UserDeletingRow
_adapter.Update(_dstErrorLog.Tables(0))
End Sub
When I delete a row, it disappears from the DataGridView but when I re-open the form, the data is all still there. Do I need to specify the DeleteCommand myself? And if so, then what is the purpose of the SqlCommandBuilder??
Use the UserDeletedRow event, not the UserDeletingRow.
In the UserDeletingRow event the changes made to your DataGridView are still not committed to the DataSource binded, so calling the SqlDataAdapter.Update in that event doesn't result in any changes to the database because the table is still unchanged.
Private Sub grdErrorLog_UserDeletedRow(sender As Object, e As DataGridViewRowEventArgs) Handles grdErrorLog.UserDeletingRow
Dim count = _adapter.Update(_dstErrorLog.Tables(0))
Console.WriteLine("Rows deleted:" & Count)
End Sub
Infact in the UserDeletingRow the argument e is a DataGridViewRowCancelEventArgs meaning that you could still cancel the deletion setting e.Cancel = True

Pass variable to new form with Datatable and Listbox

I am currently trying to write an application like address book. Listbox works properly, it shows everything corretly. But I need to pass id of chosen listbox item to another form. I got code like this in Form2:
Private myTable As New DataTable()
Public Sub LoadXml(sender As Object, e As EventArgs) Handles Me.Load
With myTable.Columns
.Add("DisplayValue", GetType(String))
.Add("HiddenValue", GetType(Integer))
End With
myTable.DefaultView.Sort = "DisplayValue ASC"
ListBox1.DisplayMember = "DisplayValue"
ListBox1.ValueMember = "HiddenValue"
ListBox1.DataSource = myTable
Dim doc As New Xml.XmlDocument
doc.Load("c:\address.xml")
Dim xmlName As Xml.XmlNodeList = doc.GetElementsByTagName("name")
Dim xmlSurname As Xml.XmlNodeList = doc.GetElementsByTagName("surname")
Dim xmlId As Xml.XmlNodeList = doc.GetElementsByTagName("id")
For i As Integer = 0 To xmlName.Count - 1
Dim nazwa As String = xmlName(i).FirstChild.Value + " " + xmlSurname(i).FirstChild.Value
myTable.Rows.Add(nazwa, xmlId(i).FirstChild.Value)
MsgBox(myTable.Rows(i).Item(1).ToString)
Next i
ListBox1.Sorted = True
End Sub
Later in the code I have event:
Public Sub ListBox1_DoubleClick(sender As Object, e As EventArgs) Handles ListBox1.DoubleClick
End Sub
I would like to know how can I call id from DataTable for selected listbox item. I hope u understand what I mean since my english is not perfect :)
Since you have added the XML value id to the data table column HiddenValue and you have assigned HiddenValue as the ValueMember for the listbox, once a record is selected in the listbox, id will be available in the listbox's [SelectedValue][1] member. For example:
Public Sub ListBox1_DoubleClick(sender As Object, e As EventArgs) Handles ListBox1.DoubleClick
MsgBox("Selected Id: " & ListBox1.SelectedValue.ToString())
End Sub