Finding combobox item - vb.net

For this question I made a simple class:
Public Class ListBoxEntry
Public Property ID As Integer
Public Property Text As String
Public Overrides Function ToString() As String
Return Text
End Function
End Class
I create some instances of this class and add them into a combobox:
...
While DR.Read
LI = New ListBoxEntry
LI.ID = DR("ID") ' ID is an integer value
LI.Text = DR(Feldname) ' Feldname is a string
cmbList.Items.Add(LI)
End While
I cannot get a working code for setting the combobox to a specific value by code.
E.g. these are my three entries (ID - Feldname):
1 - One (value 1, shown text in combobox "One")
2 - Two (value 2, shown text in combobox "Two")
3 - Three (value 3, shown text in combobox "Three")
Combobox1.SelectedIndex = somehow(2) <- here I want to set the combobox to the second entry (2), so "two" is selected
Which peace of code to I need?

You should add the instances of your class to an array or collection, then bind that to your ComboBox, e.g.
With ComboBox1
.DisplayMember = "Text"
.ValueMember = "ID"
.DataSource = myList
End With
You can then assign an ID value to the SelectedValue property of the ComboBox to select the item with that ID, e.g.
ComboBox.SelectedValue = 2
That would display "Two" in the control.

Related

Bound datagrid not showing values

I have a datagrid which is bound to a binding source which itself is populated from a list.
I can see that the binding source is populated and I can see that the datagrid has the expected number of rows to match the data in the list but i can not get the columns to populate with the data. I have tried setting the datapropertyname for the columns but to no avail. I know this is probably dead simple but I'm going round in circles.
Please can anyone help
Dim cE As New ClsEmail
Dim bs As New BindingSource
Dim dgv = Me.DataGridView1
dgv.AutoGenerateColumns = False
bs.DataSource = cE.GetMail("team#xxxx.xxxx")
With dgv.Columns(0)
.DataPropertyName = "ID"
.HeaderText = "ID"
End With
With dgv.Columns(1)
.DataPropertyName = "Subject"
.HeaderText = "Subject"
End With
dgv.DataSource = bs
When i press the button to populate the datagrid I get four rows but no values in the columns. Clearly I'm not binding the columns correctly but i can't see what I'm missing.
List(Of T) is already bindable. Rearrange your properties in your Email class like this, as the DataGridView will create the columns in property order:
Public Class Email
Public Property ID As Integer
Public Property Subject As String
Public Property DateReceived As DateTime
End Class
Then, just set the datasource like this:
With DataGridView1
.AutoGenerateColumns = True
.DataSource = cE.GetMail("team#xxxx.xxxx")
.Columns(2).Visible = False ' DataReceived (if you really intended to hide this)
End With

Two way databinding for WinForms ComboBox with separate source for Items and SelectedItem

I hope my title makes sense. I want to do the following:
Bind ComboBox Items to a list
Bind the SelectedItem to a property (separate from the list)
Update the SelectedItem of the ComboBox once something in the object changes (for example, once the property that is bound to SelectedItem changes programatically, the SelectedItem of the ComboBox also changes accordingly)
I have already achieved to do the first two things but I am stuck on point 3. The databinding only works one-way. Meaning, when I select a new Item from the ComboBox, the object in code behind changes accordingly. But if I change the object in code behind or if it has an initial value, the SelectedItem of the ComboBox is not updated/preselected.
cbErledigungsArt.DataSource = _erledigungsArten.ToArray()
cbErledigungsArt.DisplayMember = "Beschreibung"
cbErledigungsArt.ValueMember = "ID"
cbErledigungsArt.DataBindings.Add("SelectedItem", _feststellung, "ErledigungsArt")
Festellung is a custom type:
Public Class FeststellungDTO
Public Property Jahr() As Integer
Public Property ErledigungsArt() As ErledigungsArtDTO
End Class
Erledigungsart is the property that is bound to the ComboBox
Public Class ErledigungsArtDTO
Public Property ID() As Integer
Public Property Beschreibung() As String
End Class
I want to be able to say, for example:
Dim _feststellung As New FeststellungDTO() With {
.Jahr = 2015,
.ErledigungsArt = New ErledigungsArtDTO() With {.ID = 0, .Beschreibung = "Bla"}
}
Dim _erledigungsArten As New List(Of ErledigungsArtDTO)(
{
New ErledigungsArtDTO() With {.ID = 0, .Beschreibung = "Bla"},
New ErledigungsArtDTO() With {.ID = 1, .Beschreibung = "Blu"}
}
)
cbErledigungsArt.DataSource = _erledigungsArten.ToArray()
cbErledigungsArt.DisplayMember = "Beschreibung"
cbErledigungsArt.ValueMember = "ID"
cbErledigungsArt.DataBindings.Add("SelectedItem", _feststellung, "ErledigungsArt")
'SelectedItem will become "Bla"
_feststellung.ErledigungsArt = New ErledigungsArtDTO() With {.ID = 1, .Beschreibung = "Blu"}
'SelectedItem will become "Blu"
'User now selects "Bla" from the ComboBox and the value of _festellung.ErledigungsArt will change accordingly
Is this possible?

Combo Box items - Display Member for List(Of String)?

My project is in Visual Basic. I am trying to create a custom & savable "filter" for a DataGridView using several TextBoxes. Right now, any List(Of String) that is added to the Combo Box is displayed in the box as (Collection). I want my users to be able to select the one they created, so I would like the Lists to have a display name that can be selected in the Combo Box. Here is some of the code.
Dim savedFilter As New List(Of String)
savedFilter.Add(NameTextBox.Text)
savedFilter.Add(AgeTextBox.Text)
savedFilter.Add(NotesTextBox.Text)
ComboBoxSavedFilters.Items.Add(savedFilter)
Is it possible to add a display name for a List?
Or if you are lazy use buid-in generic class Tuple From MSDN.
Create collection of Tuple(Of String, List(Of String)) and use approach suggested by #Plutonix for binding collection to ComboBox
Dim savedFilter As New List(Of Tuple(Of String, List(Of String)))()
savedFilter.Add(
Tuple.Create("default",
New List From {"filter1", "filter2", "filter3"}))
savedFilter.Add(
Tuple.Create("Blue ones",
New List From {"filter4", "filter5"}))
savedFilter.Add(
Tuple.Create("Old ones",
New List From {NameTextBox.Text, AgeTextBox.Text, NotesTextBox.Text}))
With ComboBoxSavedFilters
.DisplayMember = "Item1" 'Name of first property in Tuple type
.ValueMember = "Item2" 'Name of second property in Tuple type -List
.DataSource = savedFilter
End With
Then SelectedValue will contain currently selected filter's collection,
which can be accessed like that
Dim filter As List(Of String) =
DirectCast(Me.ComboBoxSavedFilters.SelectedValue, List(Of String))
You could setup under My.Settings a StriingCollection
Initializing (you can omit the items added if so desired)
If My.Settings.Filters Is Nothing Then
My.Settings.Filters = New StringCollection() From {"One", "Two"}
End If
Setup items in a ComboBox
ComboBox1.Items.AddRange(My.Settings.Filters.Cast(Of String).ToArray)
Adding an item
My.Settings.Filters.Add(Now.ToShortDateString)
You can remove and clear items too.
Provide a Display Member for List(Of String)
Apparently, these are less a collection of filters than a collection of criteria or clauses for one Filter:
I condensed the code in the question, but there are 14 fields that can be filtered and there are multiple filters that can be applied on one field.
For the multiples per field, I am not sure I would want to store those individually, but keep the field criteria together. So, if you want to apply a name to these, a class would not only do that but could help manage the filter elements:
Public Class SuperFilter
Public Property Name As String
Public Property Elements As SortedList
Public ReadOnly Property FilterText As String
Get
Return GetFilterText()
End Get
End Property
Public Sub New(n As String)
Name = n
Elements = New SortedList
End Sub
Public Sub AddItem(filter As String)
Elements.Add(Elements.Count, filter)
End Sub
Public Sub InsetAt(index As Int32, filter As String)
Elements.Add(index, filter)
End Sub
Private Function GetFilterText() As String
Dim els(Elements.Count - 1) As String
Elements.Values.CopyTo(els, 0)
Return String.Join(" ", els)
End Function
Public Overrides Function ToString() As String
Return String.Format("{0} ({1})", Name, Elements.Count.ToString)
End Function
End Class
You would need to add methods and properties like Remove and Count but this should be enough to demonstrate. I am not sure about the SortedList, a Dictionary using the field name might be better, but something to control the order seems worthwhile. I am also unsure I would expose the Elements collection - managing it might be better left to the class.
Hopefully, the Combo displaying a set of these (as opposed to the filter elements/clauses) is the goal.
Private filters As New List(Of SuperFilter)
Add filter items to the list:
Dim item As New SuperFilter("Default")
item.AddItem("Id = 7")
filters.Add(item)
item = New SuperFilter("Blue Ones")
item.AddItem("Color = Blue")
filters.Add(item)
item = New SuperFilter("Complex")
item.AddItem("[Name] like %Bob% OR [Name] like %Alice%")
item.AddItem("AND Color = 'Blue'")
item.AddItem("AND Active=True")
item.AddItem("AND AccessRequired < 3")
item.AddItem("AND DateAdded > #2/11/2010#")
item.AddItem("AND CreatedBy = 'ziggy'")
filters.Add(item)
cbo1.DataSource = filters
cbo1.DisplayMember = "Name"
cbo1.ValueMember = "FilterText"
The value member could be the Elements - the collection of filter clauses, or it could be the query text. The GetFilterText method joins them together for you as part of what a filter manager class could/should:
For n As Int32 = 0 To filters.Count - 1
Console.WriteLine("Name: {0} Count: {1}{2}Text:{3}", filters(n).Name,
filters(n).Elements.Count,
Environment.NewLine, filters(n).FilterText)
Next
Result:
Name: Default Count: 1
Text:Id = 7
Name: Blue Ones Count: 1
Text:Color = Blue
Name: Complex Count: 6
Text:[Name] like %Bob% OR [Name] like %Alice% AND Color = 'Blue' AND Active=True AND AccessRequired < 3 AND DateAdded > #2/11/2010# AND CreatedBy = 'ziggy'
If you use "Elements" as the ValueMember you will get back the collection.
The combo displays the Name for the user. On the right, a label displays the ValueMember in this case, it is the FilterText or joined Elements. As I said, you could get back the actual collection as the SelectedValue instead, but that is available as part of SelectedItem.
If savable means beyond the life of the application instance, that is another question, but these are very easily serialized.

Unable to set valuemember/display member to bind combobox

I'm having trouble adding dynamically a combo box column to my datagridview (before you ask, yes it must be dynamic and not done in editor).
The main feature is that the combobox cell is different for each row, so it must be done using combo box cell. checkedRows is a datatable.
Name of the datagridview is editCameraTable. It already has a few columns at this point:
'create new column
Dim resComboColumn As New DataGridViewComboBoxColumn _
With {.HeaderText = "Resolution", .ReadOnly = False, .DisplayIndex = 7, .Name = "Resolution", _
.DisplayMember = "Name", .ValueMember = "ID", .DataPropertyName = "ID"}
'add combo box column
EditCameras.editCameraTable.Columns.Insert(17, resComboColumn)
addResCmbBox(checkedRows, resComboColumn)
Pretty straight forward. You'll notice I have the value member, dataproperty name, etc. Here's the addResCmbBox definition:
Public Function addResCmbBox(ByRef DT As DataTable, column As DataGridViewComboBoxColumn)
Dim resolutions As String()
'for each camera
For i As Integer = 0 To DT.Rows.Count - 1
Dim camera As camera = convertDTtoCam(DT, i)
'get the resarray
Select Case DT.Rows(i).Item("Maker").ToString.ToLower
Case "acti"
resolutions = ACTi.GetResArray(camera)
Case Else
resolutions = ACTi.GetResArray(camera)
End Select
'add items to combobox list
Dim comboCell As New DataGridViewComboBoxCell
comboCell.DataSource = resolutions
For j As Integer = 0 To resolutions.Length - 1
'set to current resolution value
If resolutions(j).TrimStart("N") = camera.res Then
comboCell.Value = resolutions(j)
End If
Next
comboCell.DisplayMember = "Name"
comboCell.ValueMember = "ID"
EditCameras.editCameraTable("Resolution", i) = comboCell
Next
Return Nothing
End Function
camera is a structure. I have no problems until I get to the displayMember and value member problem, i.e. the last line starting with "editcameras.editcameratable...".
When doing so, the exception of "The Field Name does not exist" pops up. If I don't assign the displayMember and valueMember, I have no problems. But, I can't get the value selected in the comboBox (it comes back as Null). At runtime, the combobox column has the valuemember and display name as "ID" and "Name".
How can I bind this comboboxcell to the row so that I can later get it's selected value?
UPDATE:
I did as was commented, and created a struct/class that was meant to be the resolution property:
Public Class ResolutionStruct
Property Name As String
Property ID As String
End Class
And within the loop I create a list of this class, and assign the values to it:
Dim resolutionList As New List(Of ACTi.ResolutionStruct)
For j As Integer = 0 To resolutions.Length - 1
Dim resClass As New ACTi.ResolutionStruct
resClass.Name = resolutions(j)
resClass.ID = resolutions(j)
resolutionList.Add(resClass)
Next
'set combocell values
comboCell.DisplayMember = "Name"
comboCell.ValueMember = "ID"
comboCell.DataSource = resolutionList
EditCameras.editCameraTable("Resolution", i) = comboCell
However, the comboboxCell doesn't show any value when it drops down. So, now I've bound the values but it shows nothing. Is there anything else I should be doing so that I get both the holy combo of seeing the values I'm picking AND having them be bound to the data grid view? :D
UPDATE 2
So, mea culpa. I was adding the combobox cell to the wrong column!
So now, it is showing the values. I click a value, and try to grab the selected value as as string:
Dim cmbbox2 As DataGridViewComboBoxCell = editCameraTable("Resolution", i)
resolution(i) = cmbbox2.Selected.ToString()
But it still says it's a null value! Mid build I checked the combobox props. IN fact "selected" is a boolean as false. It has no value, says it has no items as well. Any ideas on why it says it is null?
UPDATE3:
I recently resorted a different column in the table, and the values from the combo box are cleared! I guess it's really never being attached/bound in the first place.
UPDATE4:
Fixed it!!
Apparently this line:
editCameraTable.Sort(editCameraTable.Columns("ID"), System.ComponentModel.ListSortDirection.Ascending)
Caused the table to freak out! I can now get the value (woohoo!)
Right, I'll try to explain this shortly:
DisplayMember and ValueMember are supposed to be set using properties. For example you create a class containing Name and ID
Public Class Test
Property Name as String
Property ID as String
End Class
Create a few of these objects and put them in a list. Set the list as the datasource to the combobox. Now you can access the DisplayMember and ValueMember as you have written it in your code. Value would be the ID and SelectedItem would be the entire class.
What you are doing now is that you are adding a list of strings to the combobox. A String does not contain the Property Name nor ID, so naturally you can't fetch them. See it like this:
To be able to use Value and/or DisplayMember you need to be able to fetch the Property by yourself. In this case:
resolutions(j).Name
or
resolutions(j).ID
This does not work.
But for example you would be able to do this:
resolutions(j).Length
So You would be able to do this, which would display the Length in the combobox:
Combobox.DisplayMember = "Length"
To currently get the value you would have to do:
Combobox.SelectedItem.ToString()
But since you have it in a combobox column My guess is that this won't cut it since you can't fetch the value from the DataGridView.
EDIT: You are still doing this right?
<DataGridView>.Item("Resolution", i) = comboCell
Otherwise you will have empty comboboxes.
EDIT2: No need to fetch value from Combobox, get it from Grid cell instead:
<DataGridView>.Item("Resolution", i).Value
When creating the columns don't forget to set a defaultvalue to the combobox, otherwise it might be Nothing:
comboCell.DisplayMember = "Name"
comboCell.ValueMember = "ID"
comboCell.Value = resolutions(0)

Get the SelectedItem of DataGridViewComboBoxCell VB.NET

Very good afternoon to all,
The problem I have now is that I can not get the value selected as a combobox, I'm trying to set the text and value to each item in the combobox of each cell in the datagrid.
My Code:
CLASS MyListItem:
Public Class MyListItem
Private mText As String
Private mValue As String
Public Sub New(ByVal pText As String, ByVal pValue As String)
mText = pText
mValue = pValue
End Sub
Public ReadOnly Property Text() As String
Get
Return mText
End Get
End Property
Public ReadOnly Property Value() As String
Get
Return mValue
End Get
End Property
Public Overrides Function ToString() As String
Return mText
End Function
End Class
Form Load:
DataGridView1.Rows.Add()
Dim dgvcbc As DataGridViewComboBoxCell = DirectCast(DataGridView1.Rows(0).Cells(0), DataGridViewComboBoxCell)
dgvcbc.Items.Add(New MyListItem("Text to be displayed", "value of the item"))
Try to Display Selected value:
Dim oItem As MyListItem = CType(**dgvcbc.SelectedItem**, MyListItem)
MessageBox.Show("The Value of the Item selected is: " & oItem.Value)
ERROR: 'SelectedItem' is not a member of 'System.Windows.Forms.DataGridViewComboBoxCell'
If anyone has any idea how to set the values ​​and text to each item of each cell with combobox, I'd be very grateful thanks
You need to use the Value property according to the MSDN documentation:
Unlike the ComboBox control, the DataGridViewComboBoxCell does not
have SelectedIndex and SelectedValue properties. Instead, selecting a
value from a drop-down list sets the cell Value property.
To load the DataGridViewComboBoxCell you need to set the DataSource.
Depending on the type of data in the datasource, you may also need to set the DisplayMember to choose the property or column name to show in the display portion of the control and the ValueMember to choose the property or column name that is used to set the Value property of the control when an item is selected.
Here is some additional guidance from MSDN on the datasource:
Typically this property will be set for an entire column of cells
through the DataGridViewComboBoxColumn.DataSource property.
If possible, set DataSource to a source containing only the possible
selections, like a column of selections. Then the DisplayMember
property doesn't need to be set. But if the source is more
complicated, set DisplayMember to the name of the property or column
from which to retrieve possible selections.
If DataSource is set to a string array, then ValueMember and
DisplayMember do not need to be set because each string in the array
will be used for both value and display.
So in your case, you will need to do something similar to the following:
Dim cListItems As New System.Collections.Generic.List(Of MyListItem)
cListItems.Add(New MyListItem("Text to be displayed", "value of the item"))
Dim dgvcbc As DataGridViewComboBoxCell = DirectCast(DataGridView1.Rows(0).Cells(0), DataGridViewComboBoxCell)
dgvcbc.DataSource = cListItems
dgvcbc.DisplayMember = "Text"
dgvcbc.ValueMember = "Value"
Finally, if the values are the same for all cells, then you will probably want to assign the datasource to the column when you create it. All of the above code will remain the same, except you will replace the dgvcbc reference with the variable that holds the datagridviewcomboboxcolumn.