CustomObject 作为数据源不会更新控件
如果我将 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为你必须实现 IObservable 才能实现这一目标。
I think you have to implement IObservable to achieve this.
使用不同的 BindingListSorter 修复了它。
Got it fixed with a different BindingListSorter.