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:
Public Event PropertyChanged(ByVal sender As Object, _
ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
''' <summary>
''' Raises the PropertyChanged event.
''' </summary>
Protected Overridable Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
RaiseEvent PropertyChanged(Me, e)
End Sub
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:
''' <summary>
''' Handles the PropertyChanged event for all items in the collection.
''' </summary>
''' <param name="sender">
''' The item whose property value has changed.
''' </param>
''' <param name="e">
''' Contains the name of the property whose value has changed.
''' </param>
Private Sub Person_PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
If Me._sortProperty.Name = e.PropertyName Then
'A value has changed in the property by which the items are sorted so resort the collection.
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:
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!