CustomObject 作为数据源不会更新控件

发布于 2024-11-07 21:11:31 字数 5694 浏览 1 评论 0原文

如果我将 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 按钮时,网格都会添加一个新行。

现在,当我创建一个继承 BindingList(Of FooBar) 的类 FoobarList 并将 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 有什么区别?我不知道为什么这不起作用。

If I bind an BindingList(Of FooBar) to the datasource of my datagrid the controls gets updated whenever I add an item to this BindingList. For example:

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

When doing this the grid gets added a new row every time I press the New FooBar button.

Now When I create a Class FoobarList that inherits BindingList(Of FooBar) and bind an object of FoobarList to the datagrid this works exactly the same.

Now when I have a Class that inherits BindingList(Of T). When I bind an object from this Class to the datasource of a grid and add new items to it the grid doesn't get updated.

My 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

So when I Do:

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

The datagrid doesn't update it rows. The datasource obj does increase in items.

Whats the difference between this ProfelList(Of FooBar) and BindingList(Of FooBar) or FooBarList? I have no clue why this isn't working.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

自在安然 2024-11-14 21:11:31

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

I think you have to implement IObservable to achieve this.

未央 2024-11-14 21:11:31

使用不同的 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

Got it fixed with a different 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文