Using a non-collection object as a DataSource
-
10-07-2019 - |
Question
A bunch of dotnet framework components use a DataSource component. I have an object that has a number of settings that can modify the DataSource which it represents. I would like to set this object as the dropdown DataSource of a set of ComboBoxes and DataGridViewComboBoxCells.
My problem comes when trying to actually hook the thing into the ComboBox. I guess that because the changes to the DataSource can happen once the DataSource has been set, I have to use one of these BindingSource things, but the MSDN literature is pulling its usual prank of telling me what a bindingSource is without telling me what it does or how it works.
What's the best way you guys can suggest of hooking this Object up as a DataSource/BindingSource?
EDIT:
Obviously this class is junk, but it illustrates the sort of object I have now.
Most of the timing is up in the air at the moment, but basically what this shows is that my class is not a collection itself, but contains one. I need to be able to instruct the DataSource property of a ComboBox that there is a volatile list to be found here, and that it should use that list as the DataSource for its dropdown.
Public Class DynamicDataSource
Private basicList As New List(Of String)(New String() {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"})
Private _showEvensOnly As Boolean
Private _showNotContainingO As Boolean
Public Property ShowEvensOnly() As Boolean
Get
Return _showEvensOnly
End Get
Set(ByVal value As Boolean)
_showEvensOnly = value
End Set
End Property
Public Property ShowNotContainingO() As Boolean
Get
Return _showNotContainingO
End Get
Set(ByVal value As Boolean)
_showNotContainingO = value
End Set
End Property
Public Function GetDynamicList() As List(Of String)
Dim processMe As New List(Of String)(basicList)
If Me._showEvensOnly Then
For JJ As Integer = processMe.Count - 1 To 0 Step -1
If JJ Mod 2 = 0 Then
processMe.Remove(processMe(JJ))
End If
Next
End If
If Me._showNotContainingO Then
For JJ As Integer = processMe.Count - 1 To 0 Step -1
If processMe(JJ).ToUpper.Contains("O"c) Then
processMe.Remove(processMe(JJ))
End If
Next
End If
Return processMe
End Function
End Class
Solution
Short version: use BindingList<T>
...
Long version:
A DataSource
is typically either:
- an individual object (for simple binding)
- a list source (
IListSource
) - a list (
IList
)
Since you are using it for a drop-down, it sounds like you want one of the second two, typically IList
(IListSource
is relatively rare, except for DataTable
).
For changes once you have bound, you need notifications. For simple bindings (individual objects), either INotifyPropertyChanged
or *Changed
events are the way to go - but for lists you need to implement IBindingList
and raise the ListChanged
event to tell the control what happened.
To be honest, this is a lot of non-interesting work that it is very easy to make a mess of.
The pragmatic approach is to work with BindingList<T>
(possibly inheriting from it). This gives you all the list notifications, including support for items in the list changing if you implement INotifyPropertyChanged
on the items (it doesn't support *Changed
events, though).
Caveat: not all controls care about notifications... and if they don't there isn't a lot you can do about it. So if you don't see additions/swaps/etc even when using BindingList<T>
- or you don't see item updates when implement INotifyPropertyChanged
, then... er, tough?