CustomObject как источник данных не обновляет элемент управления - PullRequest
0 голосов
/ 17 мая 2011

Если я связываю BindingList (Of FooBar) с источником данных моей сетки данных, элементы управления обновляются всякий раз, когда я добавляю элемент в этот 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.

Теперь, когда я создаю класс FoobarList, который наследует BindingList (Of FooBar) и связать объект FoobarList с сеткой данных, это работает точно так же.

Теперь, когда у меня есть класс, который наследует BindingList (Of T).Когда я связываю объект из этого класса с источником данных сетки и добавляю в него новые элементы, сетка не обновляется.

Мой класс:

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 голосов
/ 18 мая 2011

Исправлено с помощью другого 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
0 голосов
/ 17 мая 2011

Я думаю, что для этого нужно реализовать IObservable.

...