Added extensions to sorting a list and improved sort.Added extensions to sorting a list and improved sort.
Old forum URL: forums.lhotka.net/forums/t/1235.aspx
Brian Criswell posted on Sunday, September 17, 2006
I have updated the ObjectListView on the CSLAcontrib site with the following improvements:
- The default item no longer creates an instance of an item in the list. It instead just holds its own set of values. This avoids problems trying to instantiate classes that must use a non-default constructor or a factory method to initialize values as well as problems trying to create an instance of an interface or abstract class.
- The sorting algorithm has been changed from a N(N-1)/2 (linear) to a N log N (binary) sort. In testing, performance of sorting 8000 items went from over five minutes to 3 seconds.
- The ObjectListView now provides two methods of changing how it sorts items in the list. An object can implement IExtendSort, or a user interface can handle the ObjectListView.ExtendSort event. The event will override the interface if both are used. This allows handling of scenarios such as a SmartDate being exposed as a string property. The ObjectListView will sort as the value as a string, so you can replace the value being sorted with the date value of the date and the ObjectListView will properly sort the "column" as a date. Check the new files for details.
The next improvement I am looking to do will be to change the way sorts are applied to be more like the DataView. So you will be able to do the following code:
ObjectListView view = new ObjectListView(myList, "Name, CreatedDate DESC");
I will most likely move IBindingListView.SortDescriptions to a private implementation and remove the redundant constructors on ObjectListView at that time, which will be a breaking change.
Please post any bug reports or suggestions here (thanks to Xal for the suggestion about the ExtendSort event).
Update: I have added a .Sort property that works like the DataView.Sort property. This has allowed the constructors to be consolidated down to 3 overloads, which is a breaking change (compile time) as only ObjectListView(IList list) carries over. I have also moved many of the IBindingListView and IBindingList methods into private implementations to simplify the exposed methods.JoeFallon1 replied on Monday, September 18, 2006
These are all nice improvements - especially the sorting time reduction.
Thanks!
I will download the latest version and do a little testing.
Seems to work fine. Thanks.
Can you add a constructor so we can skip passing String.Empty for the filter when we use this one:
public ObjectListView(IList list, string propertyName, ListSortDirection direction, string filter)
:
this(list, new ObjectView.ObjectViewPropertyDescriptor(TypeDescriptor.GetProperties(list.GetType().GetProperty("Item", new Type[] { typeof(int) }).PropertyType)[propertyName]), direction, filter)
{
}
e.g. can you add:
public ObjectListView(IList list, string propertyName, ListSortDirection direction)
:
this(list, new ObjectView.ObjectViewPropertyDescriptor(TypeDescriptor.GetProperties(list.GetType().GetProperty("Item", new Type[] { typeof(int) }).PropertyType)[propertyName]), direction, string.Empty)
{
}
Joe
Brian Criswell replied on Monday, September 18, 2006
Hi Joe,
I will address this when moving to a DataView style for the Sort property. So the constructors will look like:
- ObjectListView(IList list)
- ObjectListView(IList list, string sort)
- ObjectListView(IList list, string sort, string filter)
So in your example you would delete the list sort direction (and optionally put "DESC" into the sort). I may also include an overload for setting up the default item with values.
JoeFallon1 replied on Tuesday, September 19, 2006
Brian,
Can you address the problem with this warning: "Return type of function GetDataSource is not CLS-compliant". I get it when I build a function like the one shown below. I am not sure what it means - but I don;t want to add attributes all over the place if I don't have to.
Protected
Function GetDataSource(ByVal key As Integer) As ObjectListView
Dim filteredList As ObjectListView
'code here
Return filteredList
End FunctionBrian Criswell replied on Tuesday, September 19, 2006
Hi Joe,
I do not have that problem. So my guess is that you are using an older version of CSLA 2 that did not have the ClsCompliant attribute set. Add the following to AssemblyInfo.cs:
// Mark the assembly as CLS compliant
[assembly: System.CLSCompliant(true)]
Brian Criswell replied on Wednesday, September 20, 2006
I found an initialization bug this morning and uploaded a fixed version to CodePlex around 10:00 BST.
JoeFallon1 replied on Wednesday, September 20, 2006
Hi Brian,
A coupe of things.
1. The shorter list of constructors is a little too short. A lot of my code uses the ListSortDirection enumeration and I would like to be able to continue to use it rather than build a "DESC" string.
In my web page I have code like this:
Dim props() As String = {"code", "descr"}
Dim directions() As ListSortDirection = {ListSortDirection.Ascending, ListSortDirection.Descending}
sortedList = GetObjectListView(mList, props, directions)
The function GetObjectListView is in a Utility class:
Public Shared Function GetObjectListView(ByVal list As IList, ByVal props() As String, ByVal directions() As ListSortDirection) As ObjectListView
If list IsNot Nothing AndAlso list.Count > 0 Then
Dim properties As PropertyDescriptorCollection = TypeDescriptor.GetProperties(list.Item(0))
Dim numProps As Integer = props.GetUpperBound(0)
Dim sortDescs(numProps) As ListSortDescription
For i As Integer = 0 To numProps
sortDescs(i) =
New ListSortDescription(properties.Find(props(i), False), directions(i))
Next
Dim sortsColl As New ListSortDescriptionCollection(sortDescs)
Dim result As New ObjectListView(list, sortsColl)
Return result
Else
Return Nothing
End If
End Function
As you can see, the final call in that function is to the constructor:
public ObjectListView(IList list, ListSortDescriptionCollection sorts, string filter)
So that is another one that I would like to see kept around.
=======================================================
As to the CLS-Compliant problem - I have compiled your source code separately from CSLA2 because I am using the VB version of CSLA. I found the AssemblyInfo file in the project I use with your source code and added the attribute [assembly: System.CLSCompliant(true)].
Then I re-compiled and the problem went away. Thanks for the tip.
Joe
Brian Criswell replied on Wednesday, September 20, 2006
Hi Joe,
I wanted to keep the list of constructors as small and simple as possible. However, there is no reason why you cannot modify the code yourself or change the following line in your method from:
Dim result As New ObjectListView(list, sortsColl)
to
Dim result As New ObjectListView(list)
DirectCast(result, IBindingListView).ApplySort(sortsColl)
Alternatively, you could make a helper method that converts the the sortColl to the string for you. I do not really want to add the constructor back in as I had to replace it with the new version, and putting the old one back in would add another code path to maintain. In both the old version and the new version, all constructors pass their arguments to a single constructor that does all the work. I would have to change that to accommodate the old way of applying the sort.
Because you are using a method to generate your ObjectListView, you can absorb the impact of this change very easily.
Public Shared Function GetObjectListView(ByVal list As IList, ByVal props() As String, ByVal directions() As ListSortDirection) As ObjectListView
If list IsNot Nothing AndAlso list.Count > 0 Then
Dim sort As New System.Text.StringBuilder();
For i As Integer = 0 To props.Count - 1
If sb.Length > 0 Then
sb.Append(", ")
End If
sb.Append(props(i))
If directions(i) = ListSortDirection.Descending Then
sb.Append(" DESC")
End If
Next
Return New ObjectListView(list, sort.ToString())
End If
Return Nothing
End Function
JoOfMetL replied on Wednesday, September 20, 2006
Hi,
It is surely a stupid question, but the framework of Mr. Lhotka does not contain it not already objects SortedBindingLIst and FilteredBindingList.
It is not the same thing?
Brian Criswell replied on Wednesday, September 20, 2006
No, they are different from the ObjectListView. I started work on the ObjectListView to do a couple of things that SortedBindingList did not do.
- Automatically sort when changes are made to an item in the list. (SortedBindingList requires a method call)
- Provide easy filtering. (I had used the filtering add on for CSLA 1.x, and while it was good, I did not want to again use filter classes for filtering). This was before FilteredBindingList was created.
- Provide stable sort (I think ObjectListView provides this) that is faster than the built in .NET unstable sort. The BusinessCollectionBase class in 1.5 used .NET's built in sort and took 45 seconds to sort 8000 items. The ObjectListView takes 3 seconds.
- Provide a default item that would allow you to have a default item in a ComboBox.
- Work just like a DataView when bound to a DataGridView, including automatic sorting, filtering and cancelling of a new row but only after moving off of the row being edited.
- Implement IBindingListView so that it could be manipulated through a BindingSource.
JoOfMetL replied on Wednesday, September 20, 2006
Thank you for its precise details
JoeFallon1 replied on Thursday, September 21, 2006
Brian,
OK - I got the latest version and "took the hint" about modifying the function. I tweaked it a bit to get it to compile. <g> Then I overloaded it so a could do the same thing for a single property. That way my calling code always calls the function but if I have multiple properties then I have to add 2 lines of code to buld the 2 arrays for props and directions. Testing shows it works just fine.
I also like your list of reasons as to why this control offers more use and flexibility than the 2 that come with CSLA. My main purpose in using this was to get multi-property sorting. The filtering and performance are bonuses.
Thanks for building such a nice contrl and sharing it with the CSLA community. Once it gets more exposure and is "fully debugged" and "has all the features" it would be nice if Rocky could incorporate it directly into CSLA.
Very nice work.
Copyright (c) Marimer LLC