views:

351

answers:

2

I have a dropdown list containing the days of the week - Monday to Sunday. It is populated with a user defined type of two values that map the numeric day of the week to it's name.

Public Structure WeekDays
   Public ID As Integer
   Public Text As String
   Public Overrides Function ToString() As String
       Return Me.Text
   End Function
End Structure

The object I want to Bind to has an integer property DayOfWeek, and I want to bind the ID value of the selected item in the dropdown to the DayOfWeek property on the Object. eg. The user selects Thursday, and the ID of 4 is passed to the object.

In code I can retrieve the UDT of the SelectedItem, but I can't work out which property on the combo box to bind to.

  1. If I add the UDTs directly to the Items collection of the dropdown, the SelectedValue is Nothing.
  2. If I add the UDTs to a List(Of UDT) collection and set that as the dropdown's datasource, with the ValueMember set to ID and DisplayMember set to Text, the SelectedValue returns the whole UDT, not the ID as instructed in the ValueMember property.

Databinding seems to work really well for plain textboxes, but it seems to get way more pernickety when dealing with more complex controls.

Update: What I am looking for is the Binding statement. eg. Neither...

oB = New Binding("SelectedItem", Payroll, "DayOfWeek")
oB = New Binding("SelectedItem.ID", Payroll, "DayOfWeek")

... works. The first is just ignored (possibly because the SelectedItem property is Nothing), and the Second fails with a "Cannot bind..." error.

+1  A: 

Create Properties,

Public Structure WeekDays
    Private _ID As Integer
    Private _Text As String
    Public Sub New(ByVal ID As Integer, ByVal Text As String)
        Me._ID = ID
        Me._Text = Text
    End Sub
    Public Overrides Function ToString() As String
        Return Me._Text
    End Function

    Public Property ID() As Integer
        Get
            Return _ID
        End Get
        Set(ByVal value As Integer)
            _ID = value
        End Set
    End Property
    Public Property Text() As String
        Get
            Return _Text
        End Get
        Set(ByVal value As String)
            _Text = value
        End Set
    End Property
End Structure


Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim items As New List(Of WeekDays)

        items.Add(New WeekDays(1, "A"))
        items.Add(New WeekDays(2, "B"))

        Dim lb As New ListBox
        lb.DataSource = items
        lb.ValueMember = "ID"
        lb.DisplayMember = "Text"
        AddHandler lb.SelectedIndexChanged, AddressOf Item_Sel

        Me.Controls.Add(lb)

        TextBox1.DataBindings.Add(New Binding("Text", items, "Text"))

        Dim cb As New ComboBox
        cb.DataSource = items
        cb.DisplayMember = "Text"
        cb.ValueMember = "ID"
        cb.DataBindings.Add("SelectedValue", items, "ID")
        cb.Location = New Point(100, 100)
        Me.Controls.Add(cb)
        TextBox1.DataBindings.Add(New Binding("Text", items, "ID"))           
    End Sub

    Public Sub Item_Sel(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Dim obj As Object = CType(sender, ListBox).SelectedValue
        MsgBox(obj)
    End Sub
End Class
adatapost
Hmmm. I couldn't see why a Property would work any differently from a public Field, but I tried this anyway. After it didn't work I then tried changing from a UDT to a Class, and that didn't work either. I think your example works because you are binding to the Text property (which happens to exist in both the combo and the UDT). I need to be able to bind to the ID value, but the DataBindings.Add operation can't find an ID property on the COMBO and causes the error.
Bill
No, it has nothing to do with the ComboBox properties. You can set ValueMember and DisplayMember to any public property of the data items
Thomas Levesque
+1  A: 

OK, so I've found a possible solution.

I've created my own ComboBox control that inherits the standard WinForms.ComboBox and added an extra Integer property called SelectedID.

Public Structure NumericUDT
   Public ID As Integer
   Public Text As String

   Public Sub New(ByVal iID As Integer, ByVal sText As String)
       Me.ID = iID
       Me.Text = sText
   End Sub
   Public Overrides Function ToString() As String
       Return Me.Text
   End Function
End Structure

Public Property SelectedID() As Integer
    Get
        Dim uItem As NumericUDT
        Dim iID As Integer

        If (MyBase.SelectedItem Is Nothing) Then
            iID = 0
        Else
            uItem = DirectCast(MyBase.SelectedItem, NumericUDT)
            iID = uItem.ID
        End If

        Return iID

    End Get
    Set(ByVal value As Integer)

        Dim uItem As NumericUDT
        Dim uFound As NumericUDT = Nothing

        For Each uItem In MyBase.Items
            If uItem.ID = value Then
                uFound = uItem
                Exit For
            End If
        Next

        MyBase.SelectedItem = uFound

    End Set
End Property

This allows me to bind to the SelectedID property...

   oB = New Binding("SelectedID", Payroll, "PayDay")

...and seems to be working ok.

Bill
I'll wait a few days to see if a better solution is forthcoming, otherwise I'll accept this answer.
Bill