use checkedlistbox and get this result "system.data.datarowview" - vb.net

When I use this simple code
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles
Button1.Click
Dim cheq As New System.Text.StringBuilder
For Each item In CheckedListBox1.CheckedItems
cheq.Append(item)
cheq.Append(" ")
Next
MessageBox.Show(" Your Checked Items are : " & cheq.ToString())
End Sub
and wait for the message I find this result
Your Checked Items are : system.data.datarowview
What is the problem?

When you bind a DataTable, the data comes from its DefaultView, which is a DataView. Each item in a DataView is a DataRowView and, like most types, calling ToString on one will simply return the type name.
You are presumably setting the DisplayMember of your CheckedListBox in order to specify which column of your DataTable the values should be drawn from to be displayed in the control. If what you actually want is the text that is displayed for the item then you should be calling the GetItemText method:
Dim itemText = CheckedListBox1.CheckedItems.
Cast(Of Object).
Select(Function(o) CheckedListBox1.GetItemText(o))
MessageBox.Show("Checked Items: " & String.Join(", ", itemText))

There is no problem in the code, only a mismatch of your expectations. This CheckedListBox is bound to a datatable. When a control binds to a datatable, it actually attaches to the DataView exposed by the DefaultView property, and a DataView is a colelction of DataRowView
Presumably you want to get access to the underlying DataRow, available via the Row property of the DataRowView. It might be mostly unnecessary; you can get values out of a DataRowView in the same way as you would a DataRow; if your DataRow represents a person with a Name column then either of these will give you the name:
DirectCast(DirectCast(item, DataRowView)("Name"), String)
DirectCast(DirectCast(item, DataRowView).Row("Name"), String)
Or to tidy it a little:
For Each item In CheckedListBox1.CheckedItems.Cast(Of DataRowView)
cheq.Append(item("SOME_COLUMN_NAME_HERE"))
cheq.Append(" ")
Next

Related

Retrieving Values from sorted list based on the index of the selected item in combobox

Ok, so here is what I am trying to do:
I have names and ID's in a sorted list where the name is the key and the ID is the value. I load a combobox with the keys (names) as such:
For Each key In students.Keys
cmbStudent.Items.Add(key)
Next
In an adjacent textbox, I would like to fill the value of the selected key. I create the sorted list on the Load event. So in my mind, I would have to take the selectedItem.tostring() and search the sorted list for the value, but I can't figure it out. I've never used a sortedList before and it certainly seems like the right thing to use for this, but who knows! lol
In any event, I would really appreciate guidance as opposed to a solution otherwise I won't learn anything! Thank you!
Try this:
txtID.text = students(cmbStudent.selectedItem.ToString())
Another (less efficient) way would be to loop through all the items in the sorted list, check if it matches the key you want, and if so, then add the value to the text box.
i.e.
For Each item As KeyValuePair(Of String, String) In students
if item.Key = cmbStudent.selectedItem.ToString() then txtID.text = item.Value
Next
Regarding guidance:
You're simply extracting the value (ID in this case) from the sortedlist based on the key you pass to it (the string of the key that is being taken from the selected key in the combo-box)
Have a look at this:
https://www.tutlane.com/tutorial/visual-basic/vb-sorted-list
I filled a SortedList in Form.Load and set the display and value members of the combo. Set the DataSource to the sorted list calling .ToList since SortedList does not implement IList.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim lst As New SortedList(Of String, Integer)
lst.Add("Mathew", 1)
lst.Add("Mark", 2)
lst.Add("Luke", 3)
lst.Add("John", 4)
ComboBox1.DisplayMember = "Key"
ComboBox1.ValueMember = "Value"
ComboBox1.DataSource = lst.ToList
End Sub
Then, when the selection changes, retrieve the SelectedValue.
Private Sub ComboBox1_SelectionChangeCommitted(sender As Object, e As EventArgs) Handles ComboBox1.SelectionChangeCommitted
Dim value = ComboBox1.SelectedValue 'This returns an object but can be cast to underlying type
MessageBox.Show(value.ToString)
End Sub

How to cast Databound Gridview to Datatable?

I am trying to add row to my datagridview which is databound
Code:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
'Dim Index As Integer
'Index = DataTable1DataGridView.CurrentCell.RowIndex
Dim dt As DataTable = DataTable1DataGridView.DataSource
Dim dr As DataRow = dt.NewRow
dt.Rows.Add(dr)
End Sub
Error: Unable to cast object of type 'System.Windows.Forms.BindingSource' to type 'System.Data.DataTable'.
here
Dim dt As DataTable = DataTable1DataGridView.DataSource
you have DataSource is object and it points to System.Windows.Forms.BindingSource, not DataTable.
you need to get DataSource of the BindingSource
dim ds as DataSet =
DirectCast(DirectCast(DataTable1DataGridView.DataSource, BindingSource).DataSource, DataSet)
You're doing it all wrong. You have a BindingSource for a reason so use it. You don't need to access the DataTable at all. Just use the BindingSource, which you should be able to refer to directly, so you don't need the grid either.
Dim rowView = DirectCast(DataTable1BindingSource.AddNew(), DataRowView)
rowView("SomeColumn") = someValue
DataTable1BindingSource.EndEdit()
When you bind a DataTable, the data actually comes from the DefaultView property, which is a DataView. That's why each item is a DataRowView rather than a DataRow. You can treat a DataRowView just like you do a DataRow in many situations, including this one. If you have a typed DataSet though, you might prefer to use a typed DataRow. In that case, get the DataRow from the Row property of the DataRowView and cast it as the appropriate type:
Dim rowView = DirectCast(DataTable1BindingSource.AddNew(), DataRowView)
Dim row = DirectCast(rowView.Row, DataTable1DataRow)
rowView.SomeColumn = someValue
DataTable1BindingSource.EndEdit()

How do I add a new row to a binding source

I am trying to programmatically add a new row to a binding source . I know calling the bsSource.AddNew() adds a new row which I cast as a DataRowView and I set my values. My problem is this - the DataRowView.Row shows a RowState of detached. I do not want it to be detached ; I believe it should show added - I also do NOT want it to commit the change to the database (There is a very valid reason for this). I want to pick the time for that later.
My code is as follows:
private Sub AddToRelationSource(binID As Integer, gradeID As Integer, IsChecked As Boolean)
Dim drv As DataRowView = DirectCast(bsBinGrades.AddNew(), DataRowView)
drv.Row("IsSelected") = IsChecked
drv.Row("BinID") = binID
drv.Row("GradeID") = gradeID
' I tried drv.EmdEdit(0 drv.Row.EndEdit() - Row State still shows detached
End Sub
The BindingSource AddNew method does not actually add a new record to the underlying datasource , it simply adds it to the bindingsource as a detached item. When using the datatabel as a datasource I needed to get the datatable and use the AddRow() method - this properly set the value in my bindingsource to added so that when the changes would be committed to the database on bindingsource.Update() method.
The code I used:
Dim drv As DataRowView = DirectCast(bsData.AddNew(), DataRowView)
drv.BeginEdit()
drv.Row.BeginEdit()
drv.Row("IsSelected") = IsChecked
drv.Row.EndEdit()
drv.DataView.Table.Rows.Add(drv.Row)
The last line is what actually added the item to the datasource - I misunderstood BindingSource.AddNew() .
The following may be in the right direction. First I used a few language extension methods e.g.
Public Module BindingSourceExtensions
<Runtime.CompilerServices.Extension()>
Public Function DataTable(ByVal sender As BindingSource) As DataTable
Return CType(sender.DataSource, DataTable)
End Function
<Runtime.CompilerServices.Extension()>
Public Sub AddCustomer(ByVal sender As BindingSource, ByVal FirstName As String, ByVal LastName As String)
sender.DataTable.Rows.Add(New Object() {Nothing, FirstName, LastName})
End Sub
<Runtime.CompilerServices.Extension()>
Public Function DetachedTable(ByVal sender As BindingSource) As DataTable
Return CType(sender.DataSource, DataTable).GetChanges(DataRowState.Detached)
End Function
<Runtime.CompilerServices.Extension()>
Public Function AddedTable(ByVal sender As BindingSource) As DataTable
Return CType(sender.DataSource, DataTable).GetChanges(DataRowState.Added)
End Function
End Module
Now load ID, FirstName and LastName into a DataTable, Datatable becomes the DataSource of a BindingSource which is the BindingSource for a BindingNavigator and are wired up to a DataGridView.
Keeping things simple I mocked up data, has no assertions e.g. make sure we have valid first and last name, instead concentrate on the methods.
First use a extension method to add a row to the underlying DataTable of the BindingSource.
bsCustomers.AddCustomer("Karen", "Payne")
Now check to see if there are detached or added rows
Dim detachedTable As DataTable = bsCustomers.DetachedTable
If detachedTable IsNot Nothing Then
Console.WriteLine("Has detached")
Else
Console.WriteLine("No detached")
End If
Dim AddedTable As DataTable = bsCustomers.AddedTable
If AddedTable IsNot Nothing Then
Console.WriteLine("Has added")
Else
Console.WriteLine("None added")
End If
Since we are not talking to the database table, the primary key is not updated as expected and since you don't want to update the database table this is fine. Of course there is a method to get the primary key for newly added records if you desire later in your project.
Addition
Private Sub BindingSource1_AddingNew(ByVal sender As System.Object, ByVal e As System.ComponentModel.AddingNewEventArgs) Handles BindingSource1.AddingNew
Dim drv As DataRowView = DirectCast(BindingSource1.List, DataView).AddNew()
drv.Row.Item(0) = "some value"
e.NewObject = drv
' move to new record
'BindingSource1.MoveLast()
End Sub
'This routine takes the AddForm with the various fields that the user
'fills in and calls the TableAdapter's Insert method.
'After that is done, then the table has be be reflected back to the
'various components.
Private Sub AddRecord()
'The following line did not work because I could not get
'the bs definition down.
'Tried the BindingSource but in gave an error on
'DataRowView so I came up with an alternate way of
'adding the row.
'Dim drv As DataRowView = DirectCast(bsData.AddNew(), DataRowView)
'Dim drv As DataRowView = DirectCast(RecTableBindingSource.AddNew(), DataRowView)
'drv.BeginEdit()
'drv.Row.BeginEdit()
'drv.Row("Title") = "Order, The"
'drv.Row.EndEdit()
'drv.DataView.Table.Rows.Add(drv.Row)
RecTableTableAdapter.Insert(pAddForm.tTitle.Text,
pAddForm.tCast.Text,
pAddForm.tAKA.Text,
pAddForm.tRelated.Text,
pAddForm.tGenre.Text,
pAddForm.tRated.Text,
pAddForm.tRelease.Text,
pAddForm.tLength.Text)
Validate()
RecTableBindingSource.EndEdit()
RecTableTableAdapter.Update(VideoDBDataSet.RecTable)
RecTableAdapterManager.UpdateAll(VideoDBDataSet)
RecTableTableAdapter.Fill(VideoDBDataSet.RecTable)
VideoDBDataSet.AcceptChanges()
End Sub
'Here is my Delete Record routine
Private Sub DeleteRecordToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles DeleteRecordToolStripMenuItem.Click
Dim RowIndex As Int32
If (dgvRec.SelectedRows.Count > 0) Then
RowIndex = dgvRec.SelectedRows(0).Index
'Now we have to delete the record
dgvRec.Rows.RemoveAt(RowIndex)
dgvRec.CommitEdit(RowIndex)
dgvRec.EndEdit()
Validate()
RecTableBindingSource.EndEdit()
RecTableTableAdapter.Update(VideoDBDataSet.RecTable)
RecTableAdapterManager.UpdateAll(VideoDBDataSet)
RecTableTableAdapter.Fill(VideoDBDataSet.RecTable)
VideoDBDataSet.AcceptChanges()
Else
'No row selected to work with
End If
End Sub
'The pAddForm MUST be open for this routine to work
Private Sub UpdateGridFromForm()
Dim RowIndex As Int32
Dim Index As Int32
Dim RecIndex As Int32
Dim dt As DataTable
If ((pAddForm Is Nothing) = False) Then
RowIndex = pAddForm.GridIndex
If (RowIndex >= 0) Then
Index = pAddForm.Index
If (Index = dgvRec.Rows(RowIndex).Cells(constRecGridColIndex).Value) Then
'OK, we have a match so we are good to go
Call PopulateGridFields(RowIndex)
Else
MsgBox("Unable to save data back to the Grid because the record is no longer the same")
End If
Else
'This must be a NEW record
Call AddRecord()
End If
Else
'No form to work with
End If
End Sub
'Populate the dgvRec fields from pAddForm
Private Sub PopulateGridFields(RowIndex As Int32)
dgvRec.Rows(RowIndex).Cells(constRecGridTitle).Value = pAddForm.tTitle.Text
dgvRec.Rows(RowIndex).Cells(constRecGridCast).Value = pAddForm.tCast.Text
dgvRec.Rows(RowIndex).Cells(constRecGridAKA).Value = pAddForm.tAKA.Text
dgvRec.Rows(RowIndex).Cells(constRecGridRelated).Value = pAddForm.tRelated.Text
dgvRec.Rows(RowIndex).Cells(constRecGridGenre).Value = pAddForm.tGenre.Text
dgvRec.Rows(RowIndex).Cells(constRecGridRated).Value = pAddForm.tRated.Text
dgvRec.Rows(RowIndex).Cells(constRecGridRelease).Value = pAddForm.tRelease.Text
dgvRec.Rows(RowIndex).Cells(constRecGridLength).Value = pAddForm.tLength.Text
dgvRec.CommitEdit(RowIndex)
dgvRec.EndEdit()
Validate()
RecTableBindingSource.EndEdit()
RecTableTableAdapter.Update(VideoDBDataSet.RecTable)
RecTableAdapterManager.UpdateAll(VideoDBDataSet)
RecTableTableAdapter.Fill(VideoDBDataSet.RecTable)
VideoDBDataSet.AcceptChanges()
End Sub
'This all works great.
'The only problem I have now is that the DataGridView will
'always'Repopulate the grid (including any changes with 'Add/Delete/Modify) sending the active
'row back to the top of the grid
'I will work on a solution to this now that I have the rest working

Programmatically Change the text of a Combox

I have a user form with a combobox, with 5 unbound data items. The value of each item is of the following format: "## Explanation", a 2-digit numeric code and an explanation of the code. After the user selects an item, I would like to have the 2-digit numeric code displayed only. I have tried the following
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
ComboBox1.Text = Mid(ComboBox1.Text, 1, 2)
End Sub
However after selecting an item, the assignment doesn't seem to be working properly because ComboBox1.Text remains unchanged. Any ideas? Thanks in advance
To me, it sounds that you are not really using combo box to full potential. Looks like you want to have items with multiple pieces of info, which you're trying to combine. But here what you can do instead
Private Class ComboItem
Public Property Code As Integer
Public Property Description As String
Public ReadOnly Property Display As String
Get
Return Code & " " & Description
End Get
End Property
End Class
Dim lst As New List(Of ComboItem)()
lst.Add(New ComboItem()....) ' add your items
cboList.DataSource = lst
cboList.DisplayMember = "Display"
cboList.ValueMember = "Code"
Here where the best part starts - once user selects an item, by typing or clicking, you can do this
Dim item As ComboItem = DirectCast(cboList.SelectedItem, ComboItem)
txtCode.Text = item.Code
txtDescription.Text = item.Description
I feel, this is what you really need.
You would have to change the value in the combobox's Items collection. If you just change the Text property this is what happens:
Setting the Text property to null or an empty string ("") sets the SelectedIndex to -1. Setting the Text property to a value that is in the Items collection sets the SelectedIndex to the index of that item. Setting the Text property to a value that is not in the collection leaves the SelectedIndex unchanged.

How can I save listbox items into a string

I want to save all the items I have in my listbox into a string in this kind of format.
String = listboxitem1,listboxitem2,listboxitem3,listboxitem4,listboxitem5....
So then later once I want to pull them back up I can use a breaker and break it up, then load them into listbox1 again. I have a rough idea how to do this but not sure. I was thinking save 1 item in listbox1 at a time then separate them with "," then put it in the string. I have no idea how to put that in code though.
SOLUTION!
Found that the solution was I load it into a listbox, then I added this code
For Each Item As Object In ListBox1.Items
[StringNameHere!] &= (Item & ",")
Next
Then I load the string by splitting the string between every ","
I understand you have solved your own question. Just an additional suggestion for you if it is not a must for you to store your data as string. What if the value in your ListBox contains a "," ? It will give you another row since you are spliting it with a "," in the later part.
Try using the below:
To Store the value from ListBox:
Dim itemListToStore As New List(Of ListItem)
For Each item As ListItem In ListBox1.Items
itemListToStore.Add(item)
Next
To populate the ListBox with stored value:
For Each pullOutItem As ListItem In itemListToStore
ListBox1.Items.Add(pullOutItem.Text)
Next
This will overcome the problem of delimiter.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
dim itm_count as integer
dim s as string
s=""
itm_count= list1.items.count
For k As Integer = 0 To list1.Items.Count
s = list1.Items(k).ToString & ","
Next
MsgBox(s) 'it will shows the item separated by comas in message box
end sub