2011-05-17 20 views
0

如果我將BindingList(Of FooBar)綁定到我的數據網格的數據源,則只要向該BindingList添加項目,控件就會更新。例如:作爲數據源的CustomObject不更新控制

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 

的DataGrid不更新行。數據源obj確實增加了項目。

這個ProfelList(Of FooBar)和BindingList(Of FooBar)或FooBarList有什麼不同?我不知道爲什麼這不起作用。

回答

0

我認爲你必須實現IObservable來實現這一點。

+0

那麼爲什麼當我做FoobarList類繼承BindingList(Of FooBar)End Class – 2011-05-17 09:18:21

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