CustomObject as Datasource不更新Control

时间:2011-05-17 08:57:07

标签: vb.net datagridview datasource

如果我将BindingList(Of FooBar)绑定到我的datagrid的数据源,那么只要我将一个项添加到此BindingList,控件就会更新。例如:

Public Class FooBar
    Public Property Name As String
    Public Property Value As String
End Class

Private obj As BindingList(Of FooBar)

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    DataGridFooBars.DataSource = obj
End Sub

Private Sub btnNewFooBar(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNewFooBar.Click
    obj.Add(New FooBar() With { .Name = "Name", .Value = "Value"})
End Sub

每次按下New FooBar按钮时,网格都会添加一个新行。

现在当我创建一个继承BindingList(Of FooBar)并将FoobarList的对象绑定到datagrid的类FoobarList时,它的工作方式完全相同。

现在我有一个继承BindingList(Of T)的Class。当我将一个对象从此类绑定到网格的数据源并向其添加新项时,网格不会更新。

我的课程:

Public Class ProfelList(Of T)
    Inherits System.ComponentModel.BindingList(Of T)
    Implements IBindingList

    Private originalList As List(Of T)
    Private sortDirection As ListSortDirection
    Private sortProperty As PropertyDescriptor

    Private populateBaseList As Action(Of ProfelList(Of T), List(Of T)) = Sub(a, b) a.ResetItems(b)
    Shared cachedOrderByExpressions As New Dictionary(Of String, Func(Of List(Of T), IEnumerable(Of T)))()

    Public SortMapping As New ProfelSortMapper

    Protected Overrides ReadOnly Property SupportsSortingCore() As Boolean
        Get
            Return True
        End Get
    End Property

    Protected Overrides ReadOnly Property SortDirectionCore() As ListSortDirection
        Get
            Return sortDirection
        End Get
    End Property

    Protected Overrides ReadOnly Property SortPropertyCore() As PropertyDescriptor
        Get
            Return sortProperty
        End Get
    End Property

    Public Sub New()
        originalList = New List(Of T)()
    End Sub

    Public Sub New(ByVal enumerable As IEnumerable(Of T))
        originalList = enumerable.ToList()
        populateBaseList(Me, originalList)
    End Sub

    Public Sub New(ByVal list As List(Of T))
        originalList = list
        populateBaseList(Me, originalList)
    End Sub

    Protected Overrides Sub ApplySortCore(ByVal prop As PropertyDescriptor, ByVal direction As ListSortDirection)
        sortProperty = prop

        Dim orderByMethodName = If(sortDirection = ListSortDirection.Ascending, "OrderBy", "OrderByDescending")
        Dim cacheKey As String

        If SortMapping.ContainsKey(prop.Name.ToLower) Then
            cacheKey = Convert.ToString(GetType(T).GUID.ToString & SortMapping(prop.Name.ToLower)) & orderByMethodName
        Else
            cacheKey = Convert.ToString(GetType(T).GUID.ToString & prop.Name) & orderByMethodName
        End If

        If Not cachedOrderByExpressions.ContainsKey(cacheKey) Then
            CreateOrderByMethod(prop, orderByMethodName, cacheKey)
        End If

        ResetItems(cachedOrderByExpressions(cacheKey)(originalList).ToList())
        ResetBindings()
        sortDirection = If(sortDirection = ListSortDirection.Ascending, ListSortDirection.Descending, ListSortDirection.Ascending)
    End Sub

    Private Sub CreateOrderByMethod(ByVal prop As PropertyDescriptor, ByVal orderByMethodName As String, ByVal cacheKey As String)
        Dim sourceParameter = Expression.Parameter(GetType(List(Of T)), "source")
        Dim lambdaParameter = Expression.Parameter(GetType(T), "lambdaParameter")
        Dim accesedMember As Reflection.PropertyInfo

        If SortMapping.ContainsKey(prop.Name.ToLower) Then
            accesedMember = GetType(T).GetProperty(SortMapping(prop.Name.ToLower))
        Else
            accesedMember = GetType(T).GetProperty(prop.Name)
        End If

        Dim propertySelectorLambda = Expression.Lambda(Expression.MakeMemberAccess(lambdaParameter, accesedMember), lambdaParameter)
        Dim orderByMethod = GetType(Enumerable).GetMethods().Where(Function(a) a.Name = orderByMethodName AndAlso a.GetParameters().Length = 2).[Single]().MakeGenericMethod(GetType(T), accesedMember.PropertyType)

        Dim orderByExpression = Expression.Lambda(Of Func(Of List(Of T), IEnumerable(Of T)))(Expression.[Call](orderByMethod, New Expression() {sourceParameter, propertySelectorLambda}), sourceParameter)

        cachedOrderByExpressions.Add(cacheKey, orderByExpression.Compile())
    End Sub

    Protected Overrides Sub RemoveSortCore()
        ResetItems(originalList)
    End Sub

    Private Sub ResetItems(ByVal items As List(Of T))
        MyBase.ClearItems()

        For i As Integer = 0 To items.Count - 1
            MyBase.InsertItem(i, items(i))
        Next
    End Sub

    Protected Overrides Sub OnListChanged(ByVal e As ListChangedEventArgs)
        originalList = MyBase.Items.ToList()
    End Sub

    Public Function Find(ByVal match As System.Predicate(Of T)) As T
        Return Me.ToList.Find(match)
    End Function

    Public Function FindAll(ByVal match As System.Predicate(Of T)) As ProfelList(Of T)
        Return New ProfelList(Of T)(DirectCast(Me.ToList.FindAll(match), List(Of T)))
    End Function

End Class

所以当我这样做时:

Private obj As ProfelList(Of FooBar)

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    DataGridFooBars.DataSource = obj
End Sub

Private Sub btnNewFooBar(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNewFooBar.Click
    obj.Add(New FooBar() With { .Name = "Name", .Value = "Value"})
End Sub

数据网格不会更新它的行。数据源obj确实增加了项目。

这个ProfelList(Of FooBar)和BindingList(Of FooBar)或FooBarList之间的区别是什么?我不知道为什么这不起作用。

2 个答案:

答案 0 :(得分:0)

我认为你必须实现IObservable来实现这一目标。

答案 1 :(得分:0)

使用不同的BindingListSorter修复它。

Public Class ProfelList(Of T)
    Inherits BindingList(Of T)
    Implements IRaiseItemChangedEvents

    Private m_Sorted As Boolean = False
    Private m_SortDirection As ListSortDirection = ListSortDirection.Ascending
    Private m_SortProperty As PropertyDescriptor = Nothing

    Protected Overrides ReadOnly Property SupportsSearchingCore() As Boolean
        Get
            Return True
        End Get
    End Property

    Protected Overrides ReadOnly Property SupportsSortingCore() As Boolean
        Get
            Return True
        End Get
    End Property

    Protected Overrides ReadOnly Property IsSortedCore() As Boolean
        Get
            Return m_Sorted
        End Get
    End Property

    Protected Overrides ReadOnly Property SortDirectionCore() As ListSortDirection
        Get
            Return m_SortDirection
        End Get
    End Property

    Protected Overrides ReadOnly Property SortPropertyCore() As PropertyDescriptor
        Get
            Return m_SortProperty
        End Get
    End Property

    Protected Overrides Sub ApplySortCore(ByVal prop As PropertyDescriptor, ByVal direction As ListSortDirection)
        m_SortDirection = direction
        m_SortProperty = prop
        Dim comparer As New BOSortComparer(Of T)(prop, direction)
        ApplySortInternal(comparer)
    End Sub

    Private Sub ApplySortInternal(ByVal comparer As BOSortComparer(Of T))
        Dim listRef As List(Of T) = TryCast(Me.Items, List(Of T))
        If listRef Is Nothing Then
            Return
        End If

        listRef.Sort(comparer)
        m_Sorted = True

        OnListChanged(New ListChangedEventArgs(ListChangedType.Reset, -1))
    End Sub

    Public Function Find(ByVal match As System.Predicate(Of T)) As T
        Return Me.Find(match)
    End Function

    Public Function FindAll(ByVal match As System.Predicate(Of T)) As ProfelList(Of T)
        Return Me.FindAll(match)
    End Function

    Private Class BOSortComparer(Of J)
        Implements IComparer(Of T)
        Private m_PropDesc As PropertyDescriptor = Nothing
        Private m_Direction As ListSortDirection = ListSortDirection.Ascending

        Public Sub New(ByVal propDesc As PropertyDescriptor, ByVal direction As ListSortDirection)
            m_PropDesc = propDesc
            m_Direction = direction
        End Sub

        Private Function IComparer_Compare(ByVal x As T, ByVal y As T) As Integer Implements IComparer(Of T).Compare
            Dim xValue As Object = m_PropDesc.GetValue(x)
            Dim yValue As Object = m_PropDesc.GetValue(y)
            Return CompareValues(xValue, yValue, m_Direction)
        End Function

        Private Function CompareValues(ByVal xValue As Object, ByVal yValue As Object, ByVal direction As ListSortDirection) As Integer
            Dim retValue As Integer = 0
            If TypeOf xValue Is IComparable Then
                retValue = DirectCast(xValue, IComparable).CompareTo(yValue)
            ElseIf TypeOf yValue Is IComparable Then
                retValue = DirectCast(yValue, IComparable).CompareTo(xValue)
            ElseIf xValue IsNot Nothing AndAlso yValue IsNot Nothing AndAlso Not xValue.Equals(yValue) Then
                retValue = xValue.ToString().CompareTo(yValue.ToString())
            End If
            If direction = ListSortDirection.Ascending Then
                Return retValue
            Else
                Return retValue * -1
            End If
        End Function

    End Class
End Class