Results 1 to 3 of 3

Thread: [.NET 2.0+] Custom Typed Collections and Data-binding Support

Threaded View

  1. #3

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Dynamic Sorting

    For this example I used the project from the previous post as a starting point, modified it and I've attached the new version to this post. This new version addresses the issue I mentioned at the end of the previous post. Now, if you sort the grid, either by clicking a column header or the Sort button, and then you edit the data, the grid will resort itself automatically. How is this achieved? Read on.

    The first step was to make the Person class implement the INotifyPropertyChanged interface:
    vb.net Code:
    1. Imports System.ComponentModel
    2.  
    3. Public Class Person
    4.     Implements System.ComponentModel.INotifyPropertyChanged
    5.  
    6.     Private _id As Integer
    7.     Private _firstName As String
    8.     Private _lastName As String
    9.  
    10.  
    11.     Public Property ID() As Integer
    12.         Get
    13.             Return Me._id
    14.         End Get
    15.         Set(ByVal value As Integer)
    16.             If Me._id <> value Then
    17.                 Me._id = value
    18.                 Me.OnPropertyChanged(New PropertyChangedEventArgs("ID"))
    19.             End If
    20.         End Set
    21.     End Property
    22.  
    23.     Public Property FirstName() As String
    24.         Get
    25.             Return Me._firstName
    26.         End Get
    27.         Set(ByVal value As String)
    28.             If Me._firstName <> value Then
    29.                 Me._firstName = value
    30.                 Me.OnPropertyChanged(New PropertyChangedEventArgs("FirstName"))
    31.             End If
    32.         End Set
    33.     End Property
    34.  
    35.     Public Property LastName() As String
    36.         Get
    37.             Return Me._lastName
    38.         End Get
    39.         Set(ByVal value As String)
    40.             If Me._lastName <> value Then
    41.                 Me._lastName = value
    42.                 Me.OnPropertyChanged(New PropertyChangedEventArgs("LastName"))
    43.             End If
    44.         End Set
    45.     End Property
    46.  
    47.  
    48.     Public Sub New(ByVal id As Integer, _
    49.                    ByVal firstName As String, _
    50.                    ByVal lastName As String)
    51.         Me.ID = id
    52.         Me.FirstName = firstName
    53.         Me.LastName = lastName
    54.     End Sub
    55.  
    56.  
    57.     ''' <summary>
    58.     ''' Occurs when a property value changes.
    59.     ''' </summary>
    60.     Public Event PropertyChanged(ByVal sender As Object, _
    61.                                  ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
    62.  
    63.  
    64.     ''' <summary>
    65.     ''' Raises the PropertyChanged event.
    66.     ''' </summary>
    67.     Protected Overridable Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
    68.         RaiseEvent PropertyChanged(Me, e)
    69.     End Sub
    70.  
    71. End Class
    Now a Person object will notify any listeners each time one of its property values changes. This has two effects:

    1. If we edit a property value of a Person object in code, that change will be reflected automatically in any bound controls. That's because bound controls listen for the PropertyChanged event of the items they're bound to.

    2. Our collection knows when a property value of an item changes so it can resort itself if necessary.

    The second effect is what we're specifically interested in here. In order to implement this we must first add an event handler to the PersonCollection class to handle the PropertyChanged event of its items:
    vb.net Code:
    1. ''' <summary>
    2. ''' Handles the PropertyChanged event for all items in the collection.
    3. ''' </summary>
    4. ''' <param name="sender">
    5. ''' The item whose property value has changed.
    6. ''' </param>
    7. ''' <param name="e">
    8. ''' Contains the name of the property whose value has changed.
    9. ''' </param>
    10. Private Sub Person_PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
    11.     If Me._sortProperty.Name = e.PropertyName Then
    12.         'A value has changed in the property by which the items are sorted so resort the collection.
    13.         Me.ApplySortCore(Me._sortProperty, Me._sortDirection)
    14.     End If
    15. End Sub
    Now, this method is supposed to handle the PropertyChanged event for all the items in the collection and none that aren't. This doesn't happen automatically. We need to attach the event handler as an item is added to the collection and, just as importantly, we need to detach the event handler as an item is removed from the collection:
    vb.net Code:
    1. ''' <summary>
    2. ''' Removes all elements from the collection.
    3. ''' </summary>
    4. Protected Overrides Sub ClearItems()
    5.     'Detach event handlers from all items.
    6.     For Each item As Person In Me.Items
    7.         RemoveHandler item.PropertyChanged, AddressOf Person_PropertyChanged
    8.     Next
    9.  
    10.     MyBase.ClearItems()
    11. End Sub
    12.  
    13. ''' <summary>
    14. ''' Inserts the specified item in the list at the specified index.
    15. ''' </summary>
    16. Protected Overrides Sub InsertItem(ByVal index As Integer, ByVal item As Person)
    17.     MyBase.InsertItem(index, item)
    18.  
    19.     'Attach event handlers to the item being added.
    20.     AddHandler item.PropertyChanged, AddressOf Person_PropertyChanged
    21. End Sub
    22.  
    23. ''' <summary>
    24. ''' Removes the item at the specified index.
    25. ''' </summary>
    26. Protected Overrides Sub RemoveItem(ByVal index As Integer)
    27.     'Detach event handlers from the item being removed.
    28.     RemoveHandler Me.Items(index).PropertyChanged, AddressOf Person_PropertyChanged
    29.  
    30.     MyBase.RemoveItem(index)
    31. End Sub
    32.  
    33. ''' <summary>
    34. ''' Replaces the item at the specified index with the specified item.
    35. ''' </summary>
    36. Protected Overrides Sub SetItem(ByVal index As Integer, ByVal item As Person)
    37.     'Detach event handlers from the item being removed.
    38.     RemoveHandler Me.Items(index).PropertyChanged, AddressOf Person_PropertyChanged
    39.  
    40.     MyBase.SetItem(index, item)
    41.  
    42.     'Attach event handlers to the item being added.
    43.     AddHandler item.PropertyChanged, AddressOf Person_PropertyChanged
    44. End Sub
    That looks after resorting when existing items are edited. We need only extend that slightly to resort the collection when new items are added:
    vb.net Code:
    1. ''' <summary>
    2. ''' Inserts the specified item in the list at the specified index.
    3. ''' </summary>
    4. Protected Overrides Sub InsertItem(ByVal index As Integer, ByVal item As Person)
    5.     MyBase.InsertItem(index, item)
    6.  
    7.     'Attach event handlers to the item being added.
    8.     AddHandler item.PropertyChanged, AddressOf Person_PropertyChanged
    9.  
    10.     If Me._sortProperty IsNot Nothing Then
    11.         'Ensure that the collection maintains the correct sort order.
    12.         Me.ApplySortCore(Me._sortProperty, Me._sortDirection)
    13.     End If
    14. End Sub
    15.  
    16. ''' <summary>
    17. ''' Replaces the item at the specified index with the specified item.
    18. ''' </summary>
    19. Protected Overrides Sub SetItem(ByVal index As Integer, ByVal item As Person)
    20.     'Detach event handlers from the item being removed.
    21.     RemoveHandler Me.Items(index).PropertyChanged, AddressOf Person_PropertyChanged
    22.  
    23.     MyBase.SetItem(index, item)
    24.  
    25.     'Attach event handlers to the item being added.
    26.     AddHandler item.PropertyChanged, AddressOf Person_PropertyChanged
    27.  
    28.     If Me._sortProperty IsNot Nothing Then
    29.         'Ensure that the collection maintains the correct sort order.
    30.         Me.ApplySortCore(Me._sortProperty, Me._sortDirection)
    31.     End If
    32. End Sub
    Now, if the collection is currently sorted, it is resorted each time a new item is added.

    To test this out, try running the attached project and click a column header to sort the grid by that column. Now try editing a cell in that column such that it would make the rows out of order. Note that when you navigate away from that cell the grid resorts to maintain correct order in the sorted column. Now try entering new values in the controls at the bottom of the form and hitting the Add button. Make sure that adding the new item at the bottom of the grid would make the rows out of order. Note that the grid resorts itself such that the new item is placed to maintain correct order in the sorted column.

    Again, I should point out that this code has not been implemented in the most efficient way possible. I've used the easiest way to provide sorting but the best way would require some more work. For instance, when an item is added, at the moment it is added to the end of the collection and the grid will update, then the collection is resorted and the grid will update again. In this example you don't see a difference and there are so few items that everything happens quickly enough that it doesn't matter. With a larger number of items it might become apparent that the grid was refreshing twice. Ideally we would avoid updating the grid twice by ensuring that the new item is inserted at the correct index to begin with. I'll look at optimising this code at a later time. Stay tuned!
    Attached Files Attached Files
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width