I have been simple-binding the Text property of a TextBox for some time using a DataTable like so:
Dim dtbData As New DataTable
' populate table
Me.BindingSource.DataSource = dtbData
txtBox.DataBindings.Clear()
txtBox.DataBindings.Add(New Binding("Text", Me.BindingSource, "OrderNumber", True))
BindingNavigator1.BindingSource = Me.BindingSource
However, I am trying to change this to use a List(Of CustomObject) instead. I am simply using the dtbData to populate the List and set the DataSource to the List instead. I have set a breakpoint, and the DataTable and List are both populated. If I comment out the line that adds the Binding to the txtBox, then the BindingNavigator works as expected, but if I leave it alone, the binding does not work.
Here is what I've tried:
Dim lstData As New List(Of CustomObject)
Dim dtbData As New DataTable
' populate table
For Each row As DataRow In dtbData.Rows
Dim obj As New CustomObject
obj.OrderNumber = CInt(row("OrderNumber"))
lstData.Add(obj)
Next
Me.BindingSource.DataSource = lstData
txtBox.DataBindings.Clear()
txtBox.DataBindings.Add(New Binding("Text", Me.BindingSource, "OrderNumber", True))
BindingNavigator1.BindingSource = Me.BindingSource
It seems like it should work the same. Instead of a DataTable, the BindingSource is a List(Of CustomObject) though, so I'm not sure if I have to do something differently. The property names being bound are still the same. I have also tried Me.BindingSource.Current in the Binding but that doesn't work either. Can anyone tell me what I am doing incorrectly?
The CustomObject looks like so:
Public Class CustomObject
Public OrderNumber As Integer
End Class
EDIT
I added a Try/Catch block around the binding, and I see the following error message:
Cannot bind to the property or column OrderNumber on the DataSource. Parameter name: dataMember
I just don't see what is different between binding to the OrderNumber column of a DataTable or the OrderNumber property of a CustomObject.
I realized what the problem was. The OrderNumber wasn't defined as a Property of my CustomObject. I changed the definition to this:
Public Class CustomObject
Public Property OrderNumber As Integer
End Class
And now it allows me to bind the Text property of a TextBox to the OrderNumber property of my CustomObject.
Related
I created a datatable containing the list of notes for songs:
Private Table As New DataTable
Public Sub New()
With Table
.Columns.Add("Name")
.Columns.Add("NoteList")
.Rows.Add("GOT", GOT)
.Rows.Add("Yesterday", Yesterday)
End With
End Sub
GOT and Yesterday are lists of notes (notes is a class containing note, duration etc..)
On the form I then assign the datatable to a combobox:
ComboSongs.DisplayMember = Songs.DataTable.Columns(0).ColumnName
ComboSongs.ValueMember = Songs.DataTable.Columns(1).ColumnName
ComboSongs.DataSource = Songs.DataTable
I try to get the list of notes like this:
Dim songToPlay As List(Of Note) = CType(ComboSongs.SelectedValue, List(Of Note))
When I try to get the list I get the error:
System.InvalidCastException: 'Unable to cast object of type 'System.String' to type 'System.Collections.Generic.List`1[test.Note]'.'
Now I am unsure where I am getting it wrong. What would be the correct way to do this?
Your ValueMember is what is returned through the ComboBox.SelectedValue. So since you set the ValueMember like this
ComboSongs.ValueMember = Songs.DataTable.Columns(1).ColumnName
you only get the ColumnName. I assume that's a string and, well, the error message tells you it is one
... Unable to cast object of type 'System.String' ...
I guess that should be "NoteList", since that would be returned by Songs.DataTable.Columns(1).ColumnName
But this all doesn't make much sense, as I guess you are selecting a song there, either "Yesterday" or "GOT". At the point you're at it's so convoluted to return the DataTable rows, and index them. You will need to find the row by name and that is just too complicated when you could just create a class with strong names. I'll give you a class based solution but I'm not sure if you can make that change.
Private Class Song
Public Property Name As String
Public Property NoteList As List(Of Note)
End Class
Private Class Note
' your implementation
End Class
Dim songs As New List(Of Song)()
songs.Add(New Song() With {.Name = "GOT", .NoteList = New List(Of Note)})
songs.Add(New Song() With {.Name = "Yesterday", .NoteList = New List(Of Note)})
' need to populate those NoteLists first
ComboSongs.DisplayMember = "Name"
ComboSongs.DataSource = songs
Dim songToPlay = songs.SingleOrDefault(Function(s) s.Name = ComboSongs.SelectedValue)
Dim noteList = songToPlay.NoteList
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
I am facing a problem in my VB.Net code.
I have an object factuurregel with the following properties:
Property Id As Integer
Property Medewerker As Medewerker
Property Datum As DateTime
Property Activiteit As Activiteit
Property Omschrijving As String
Property Tijd As Decimal
Property Tarief As Decimal
Property Specificatie As Boolean
Property Factureren As Boolean
Property NietFactureren As Boolean
Property Klant As FactKlant
Property Project As String
Another object I am using there is activiteit:
Property Id As Integer
Property Omschrijving As String
Property FactuurRegel As String
In a form, I have a datagrid, where I use following code:
Dim lActiviteiten As New List(Of Activiteit)
lActiviteiten = LoadActiveiten()
Dim dgAct As DataGridViewComboBoxColumn = DataGridUren.Columns(3)
dgAct.DataSource = lActiviteiten
AND
loadmwlist()
Dim dgMW As DataGridViewComboBoxColumn = DataGridUren.Columns(1)
With dgMW
.ValueMember = dtmw.Columns("ID").ToString
.DisplayMember = dtmw.Columns("Naam").ToString
.DataSource = dtmw.Copy
End With
where loadmwlist fills a table.
With both codes, the combobox in the datagrid is filled correct.
The problem is, when I set the object factuurregel as datasource, only in the medewerker combobox the right value is displayed.
To be complete, the object medewerker is build like this:
Property Id As Integer
Property Naam As String
Why is the datasource correct when I use a table as datasource for the combobox, but not when I use a list of objects?
jmcilhinney said:
Why are you doing this: .ValueMember = dtmw.Columns("ID").ToString
instead of this: .ValueMember = "ID"? Where are you setting the
DisplayMember and ValueMember of dgAct? I'm not sure that you know
what those properties actually do, so you probably ought to read up on
them. –
after which I added
dgAct.DisplayMember = "Omschrijving"
dgAct.ValueMember = "Id"
Code is working as it should now.
I have an ArrayList with objects, this ArrayList is used as a DataSource to a ListBox. When new objects are added to the listbox, how can i get the listbox to update?
the code for populating the list looks lite this:
'Form1.ExistingArticles = The ArrayList
'Form1.LB_Articles = The Listbox
Public Sub FillArticleList()
If Form1.ExistingArticles.Count = 0 Then
Exit Sub
End If
Form1.LB_Articles.DataSource = Form1.ExistingArticles
Form1.LB_Articles.ValueMember = "ID"
Form1.LB_Articles.DisplayMember = "ListText"
End Sub
When i add a new object to the Form1.ExistinArticles i can see that the new object is there, but it does not update. Calling FillArticleList() again will not work either.
Firstly, if you're targeting .NET 2.0 or later then you shouldn't be using an ArrayList at all. The List(Of T) basically superseded the ArrayList and is what you should use in most cases.In this case, you can either use a List(Of T) and bind it to a BindingSource and bind that to the ListBox or else use a BindingList(Of T). Both the BindingSource and BindingList(Of T) have methods that you can call when you make changes to the list to update and bound control(s).
I need a simple way to fill the value from database of the current item being added so that I can use it later :
'Filling the MAIN Categories part
Dim DataAdapterCatm As New MySqlDataAdapter("SELECT id,title From catM;", MySqlConnection)
Dim dsMc As New DataTable
DataAdapterCatm.Fill(dsMc)
For counter = 0 To dsMc.Rows.Count - 1
LbMCat.Items.Add(dsMc.Rows(counter).Item("title").ToString)
'LbMCat.ValueMember = dsMc.Rows(counter).Item("id").ToString
'The above line don't work, I need something to replace it
Next
You are misunderstanding what ValueMember means. ValueMember is a string which represents the property that you wish to use as the value. In your case it would be just "id". Notice that it is a property of the ListBox - it is not different for each time.
ValueMember and the related DisplayMember are only valid when using DataBinding with the DataSource property and it not valid when manually adding items to the ListBox via Items.Add. What you want is the following:
Dim DataAdapterCatm As New MySqlDataAdapter("SELECT id,title From catM;", MySqlConnection)
Dim dsMc As New DataTable
DataAdapterCatm.Fill(dsMc)
LbmCat.DataSource = dsMc;
LbMCat.ValueMember = "id";
LbmCat.DisplayMember = "title";
try this in place of both lines in your for loop:
LbMCat.Items.Add(New ListItem(dsMc.Rows(counter).Item("title").ToString(), dsMc.Rows(counter).Item("id").ToString())
In the constructor for ListItem you can specifiy both the value and the text for the ListItem