Can I make a combobox that is stronly typed?

A

active

I'm using a ComboBox to display objects of a class I've defined, say CQQ.

Works great except somehow I occasionally set an Item to a String object
instead of an object of type CQQ.

It looks like Text replaces an item or something like that.

This results in a runtime error at which time I learn that the item that
should be CQQ is a String.

I can't find out where or how the setting happens.

It occurs to me that if the comboBox defined it's Items as objects of type
CQQ instead of Object it would the usage would be less error prone and more
likely to be bug free.

Is there some way I could generate a strongly typed combobox?

I know I could simply inherit a combobox and try to override anything the
changes an Item but that leaves the possibility that I'd miss some method
and not really have what I want. I'd like to just change the Items
collection once.

Is that possible?


Thanks
 
R

RobinS

Why not create a list of CQQ and then bind the combobox to it. Then to add
anything to the combobox, you'll have to add it to the list, which will
blow up if you try to add an object other than a CQQ to it. Off the top of
my head, something like this:

Dim myList As List(Of CQQ)

'add entries to the list
myList.Add(New CQQ("field1", "field2"))
myList.Add(New CQQ("field1", "field2"))
myList.Add(New CQQ("field1", "field2"))

myComboBox.DataSource = myList
myComboBox.DisplayMember = myList.field2
myComboBox.ValueMember = myList.field1

Robin S.
 
A

active

Because I know nothing about using a datasource.

I'll look into what you've given below and see if I can learn enough to use
it.

There is also SetItemCore and SetItemsCore that I have to look into.


Thanks a lot
 
A

active

I've used what you suggested almost with no changes.

Below is what I've tried and it appears to be storing data but not
displaying it.

I've tried everything I can think of for the DisplayMember!

StringWithInteger has two properties: Str and Value



Public myList As List(Of StringWithInteger) = New List(Of StringWithInteger)

and

myList.Add(itemValue) 'itemValue is type StringWithInteger

and

Public Sub New()

MyBase.New()

InitializeComponent()

Me.DataSource = myList

Me.DisplayMember = myList.field2

Me.ValueMember = myList.field1

End Sub
 
A

active

This is the attempt that seems like it should work but I get nothing in the
drop down box even though the debugger shows myList to have 187 items
StringWithInteger has two properties: Str and Value

Public myList As List(Of StringWithInteger) = New List(Of
StringWithInteger)

and

myList.Add(itemValue) 'itemValue is type StringWithInteger

and

Public Sub New()

MyBase.New()

InitializeComponent()
MyBase.DataSource = myList

MyBase.DisplayMember = "Str"

MyBase.ValueMember = "Value"
 
C

Cor Ligthert [MVP]

Active,

If you know nothing from a datasource, why do you than try to use it direct
on your own usercontrol.

Can you not first try it as Robin show you on a normal combobox and then
start to implement that on your own usercombobox?

Just my thought,

Cor
 
R

RobinS

Can you show your class definition for StringWithInteger?

Robin S.
-------------------------------
 
A

active

Cor Ligthert said:
Active,

If you know nothing from a datasource, why do you than try to use it
direct on your own usercontrol.

Can you not first try it as Robin show you on a normal combobox and then
start to implement that on your own usercombobox?

I did just that. In fact I gave the combobox properties so the form can
supply the List and set the DisplayMember and the ValueMember so the
combobox is somewhat general purpose.

However I don't know how to "unbind" the list and then rebind it.
I need to do that because changing the list after it is bound does not
change the boxes display.
That is, how do I undo .DataSource = myList

Thanks




thanks
 
A

active

I think I have a new problem now.
I don't know how to "unbind" the list and then rebind it.
I need to do that because changing the list after it is bound does not
change the box's display.
That is, how do I undo .DataSource = myList
so I can change myList and the rebind it?

Thanks


RobinS said:
Can you show your class definition for StringWithInteger?


I think I'm past the earlier problem now (see above) but since you asked
I've added the class below. I removed some to make it easier to read.

Public Class StringWithInteger
Private mInteger As Integer
Private mString As String

Public Sub New(ByVal str As String, ByVal value As Integer)
mString = str
mInteger = value
End Sub
Public Overrides Function ToString() As String
ToString = mString
End Function
Public Property Str() As String
Get
Str = mString
End Get
Set(ByVal text As String)
mString = text
End Set
End Property
Public Property Value() As Integer
Get
Value = mInteger
End Get
Set(ByVal numb As Integer)
mInteger = numb
End Set
End Property
End Class
 
C

Chris Dunaway

I did just that. In fact I gave the combobox properties so the form can
supply the List and set the DisplayMember and the ValueMember so the
combobox is somewhat general purpose.

However I don't know how to "unbind" the list and then rebind it.
I need to do that because changing the list after it is bound does not
change the boxes display.
That is, how do I undo .DataSource = myList

Thanks

thanks

Instead of using List(Of StringWithInteger), try using BindingList(Of
StringWithInteger)

Chris
 
A

active

Chris

Chris, Does your reply relate to the above question or to the entire
requirement?
My next problem will relate to sorting the box's displayed list.
Does that impact the usage of either List or BindingList

Thanks
 
R

RobinS

I recommend you use a BindingSource component between the data source and
the combobox. You can drag one onto the form from the Toolbox, or create it
="on the fly".

Dim myBindingSource As BindingSource = New BindingSource()

myBindingSource.DataSource = myList

myComboBox.DataSource = myBindingSource
myComboBox.ValueMember = "whatever"
myComboBox.DisplayMember = "whatever"

Now when you change the list, the BindingSource will respond, and then
repaint the control. The BindingSource is sort of like lubrication between
the data source and the control. Putting it in the middle gives you a bunch
of methods and properties you can access, and better controls the bound
data and the display of it.

As Chris Dunaway recommended, you could define your list as a
BindingList(Of T), but you would still probably want to use a BindingSource
for the reason mentioned above.

Give this a try, and let me know how it works.

Robin S.
 
A

active

To update the display, what I previously had to do was rebind the list each
time I changed the list.
That seemed to work OK.
I inserted the BindingSource as you recommended and no longer need to rebind
after changes.
Chris Dunaway didn't really recommend. He suggested I try BindingList(Of T).
I did and didn't notice any difference.
I tried reading about all the stuff you and Chris suggested - but my
background is lacking and it is pretty slow going.
So I really want to thanks you for all the help. Now at least I know what I
need to read until I understand it.
Strange to have it working and not understand what is going on.

The List class seems a little simpler so I'd prefer to stay with that unless
there is a strong reason to use BindingList - is there such a reason?

I've been looking at internet sites trying to find out how to sort the
ComboBox display. Can you easily point me to something that would help?

Thanks again for all the help!

PS
I still make changes by changing the list.
The BindingSource doc seemed to say that changes in the data can be made
through it. Should I be looking at doing that?
 
R

RobinS

I figured the BindingSource would fix your problem.

For binding to a combobox, I think a BindingList is overkill. I use a
BindingList when binding a list of my business objects to a DataGridView so
I can access the methods and properties of the bindinglist and override
them as needed. There's no reason for you to not use a List() if it works
for you.

If you are loading the combobox from a datatable, sort it when you pull it
from the database. "Select LastName, FIrstName From MyCustomerTable ORDER
BY Lastname, FirstName".

If that's not viable, the BindingSource has sort capabilities. (See what I
mean about it having methods and properties you can use? Hubba hubba.)

For example, this will sort the data in my CustomersBindingSource by
ContactName in Ascending order.

CustomersBindingSource.Sort = "ContactName ASC"

There's probably also some kind of sort property on the combobox, but I'm
too tired to look it up. ;-)
I still make changes by changing the list.
The BindingSource doc seemed to say that changes in the data can be made
through it. Should I be looking at doing that?

I think it's talking about when you want to change the data and save it
back to the data source, like when you are binding the data to a
DataGridView. You don't need to worry about that at this point.

I'm glad it's working. Good luck.
Robin S.
Ts'i mahnu uterna ot twan ot geifur hingts uto.
-----------------------------------------------
 
A

active

I have a feeling I'm taking advantage of you good nature, but I can't stop!

After I wrote last night, I found the SortedList generic class

Which works OK and produces a sorted display.

However, there is something I can't figure out:

I need to get the integer part of StringWithInteger (Value) of the selected
item

I got this far
= DirectCast(StringWithIntegerComboBox1.SelectedItem, SortedList(Of String,
StringWithInteger))

StringWithInteger has two properties Str and Value

I don't think I want to cast to SortedList but something like
SortedList.Item

That's my present problem.

Thanks again

I'll also try List with the sort method you pointed out but I would like to
know how to do the above.



a smaller problem is in understanding. I continue to use

StringWithIntegerComboBox1.ItemDisplayMember = "Str"

StringWithIntegerComboBox1.ItemValueMember = "Value"

With List there was only one object so I could see how that might work.

With SortedList there are two objects and I wonder how it finds the property

It appears to find it because I tried

StringWithIntegerComboBox1.ItemDisplayMember = "qqStr"

StringWithIntegerComboBox1.ItemValueMember = "qqValue"

and this produced an exception which makes me think that it was using the
original one - not ignoring them

Suppose both objects had a property "Value", then what?
 
R

RobinS

You're on the right path with the DirectCast, but you need to cast it to
the object that is in the sortedlist, not to a SortedList itself.

In your sorted list, I'm assuming StringWithInteger is still a class with
both fields in it. Did you try this:

myItem = _
DirectCast(StringWIthIntegerComboBox1.SelectedItem, _
StringWithInteger)

Debug.Print(myItem.str)
Debug.Print(myItem.Value.ToString)

As for the data binding, my guess would be it sorts by the first value, but
it retains the list of objects (second value). So it data binds to the
objects in the list, and only uses the key to sort them.

Robin S.
------------------------------------------
 
A

active

I came up with the following for SortedList(Of String, StringWithInteger)

'ControlGenericComboBox1.SelectedItem is of type:
System.Collections.Generic.KeyValuePair(Of String, .StringWithInteger)

'And has properties Key and Value

and

DirectCast(ControlGenericComboBox1.SelectedItem,
System.Collections.Generic.KeyValuePair(Of String,
StringWithInteger)).Value.Numb

where Numb is a property of my class



Also, ComboBox disallows sort if a datasource is used.



Also, with

List(Of StringWithInteger)

I couldn't get the following to work.

The doc's seem to say it should.

BindingSource1.Sort = "Str ASC"

Just occurred to me: I wonder if

System.Collections.Generic.KeyValuePair

applies here.



Thanks for all the help
 
R

RobinS

You're welcome. I'm glad you got it to work for you.
Robin S.
------------------------------
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top