Using a non-collection object as a DataSource

2019-04-02 11:17发布

问题:

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

回答1:

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?