This article builds upon the code started in GridView and ObjectDataSource with custom objects.
An ObjectDataSource really only works with two types of data, DataTables and object that implement IEnumerable. If you pass it any other type of object, it is converted into an IEnumerable object. DataTables have sorting abilities built-in, custom objects are required to use the SortParameterName of the ObjectDataSource.
The idea is pretty simple, taking our ObjectDataSource tag from our previous version we add SortParameterName, and enable sorting on the GridView:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
DataObjectTypeName="Person" TypeName="PersonAdapter"
DeleteMethod="DeletePerson" InsertMethod="InsertPerson"
SelectMethod="GetAll" UpdateMethod="UpdatePerson"
SortParameterName="sortExpression" />
<asp:GridView ID="GridView1" runat="server" AllowPaging="True"
DataKeyNames="Name" DataSourceID="ObjectDataSource1"
AutoGenerateDeleteButton="True" AutoGenerateEditButton="True"
AutoGenerateColumns="True" AllowSorting="true" />
Next, we add a method to our TableAdapter to handle this parameter:
public PersonList GetAll(String sortExpression) {
PersonList people = GetAll();
switch (sortExpression) {
case "Name":
case "Name ASC":
people.Sort(PersonComparer.CompareByName);
break;
case "Name DESC":
people.Sort(PersonComparer.CompareByNameDesc);
break;
case "Title":
case "Title ASC":
people.Sort(PersonComparer.CompareByTitle);
break;
case "Title DESC":
people.Sort(PersonComparer.CompareByTitleDesc);
break;
}
return people;
}
The SortParameterName property is passed a string of comma-separated field names, optionally followed by "ASC" or "DESC" to indicate direction. For this example, I'm not handling multiple field sorts. Also, notice I did not add an Attribute to this method as I did in the previous methods - this is because I do not want this method listed in the ObjectDataSource configure wizard, and the sortExpression will be passed in automatically anytime SortParameterName is set.
The PersonComparer class is a helper class I created to manage the sort logic. Since my PersonList is really a List<>, I can use the Sort method to do most the work, I just need to tell it how to compare objects. Here is the code for the class:
using System;
using System.Collections.Generic;
sealed class PersonComparer
{
private static IComparer<Person> _compareByName = new _sortName(false);
public static IComparer<Person> CompareByName { get { return _compareByName; } }
private static IComparer<Person> _compareByNameDesc = new _sortName(true);
public static IComparer<Person> CompareByNameDesc { get { return _compareByNameDesc; } }
private class _sortName : IComparer<Person> {
bool _reverse;
public _sortName(bool reverse) {
this._reverse = reverse;
}
#region IComparer<Person> Members
public int Compare(Person x, Person y) {
if (_reverse) return y.Name.CompareTo(x.Name);
else return x.Name.CompareTo(y.Name);
}
#endregion
}
private static IComparer<Person> _compareByTitle = new _sortTitle(false);
public static IComparer<Person> CompareByTitle { get { return _compareByTitle; } }
private static IComparer<Person> _compareByTitleDesc = new _sortTitle(true);
public static IComparer<Person> CompareByTitleDesc { get { return _compareByTitleDesc; } }
private class _sortTitle : IComparer<Person> {
bool _reverse;
public _sortTitle(bool reverse) {
this._reverse = reverse;
}
#region IComparer<Person> Members
public int Compare(Person x, Person y) {
if (_reverse) return y.Title.CompareTo(x.Title);
else return x.Title.CompareTo(y.Title);
}
#endregion
}
}
The class is sealed just to be on the safe side - no one should be deriving anything from this class. In fact, everything is static so there is no need to create an instance of the class to use it. The List.Sort method has an overload to take an object that supports IComparer<>, and this is used for the actual comparison. A boolean is used to control the sort direction, but to hide this implementation detail from the user a set of public static members are exposed.
If you think this is starting to add up to a good deal of code, well I agree. Some of this could be trimmed down using reflection, but I tend to shy away from reflection given it's reputation for performance problems. If I'm working with a small set of fields (like managing role providers), this is my preferred method, but when it's time to scale up there is another option: DataTables. DataTables aren't tied down to XSD's and TableAdapters, they are free to date other people, and in the next article (in what is quickly becoming a series) we will look at moving this code from a List generic to a DataTable.
Update: If you are curious to see another approach, Dylan has started a set of posts on GridView sorting using reflection. Well worth the read.
Posted By Mike On Tuesday, April 17, 2007
Filed under asp.net gridview |
Comments (11)
Dave Johnson
-
Thursday, July 19, 2007
11:47:37 PM
Thanks so much for posting this. Very clearly explained and it solved my sorting problems!
Cheers
Brent
-
Wednesday, December 05, 2007
5:34:36 PM
Hi Mike,
Great article!
I am really interested in the next article you advertise as moving this code from a List to a Datatable, but I can't seem to find it. Is it up on your site?
Thanks
Mike
-
Thursday, December 06, 2007
2:05:02 AM
Hi Brent - I never did post the next article, doh! Look for a post soon to complete the trilogy!
Mojtaba Vali
-
Thursday, May 01, 2008
7:12:21 AM
what about a 3tier program and bind dynamically?(only a dataset)
pradnya
-
Friday, February 20, 2009
1:17:16 AM
m trying to filter teleric grid column using isnull fitering option in .net 3.0 version but it dispalys following error message
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
please help regarding this.
Thanks
Mike
-
Friday, February 20, 2009
9:06:11 AM
I've not used Telerik's Grid control, you should check the support section of their site, and forums at http://www.telerik.com/support.aspx
Ammar
-
Monday, April 27, 2009
9:43:03 AM
I can't speak enough about your nice article.
It helped me out so much, and I am happy to post this recommendation.
Anybody looking for sorting prototype, just get in this article without seeing the others, I already get tuff of seeing other !
Thank you once again
Cobi
-
Tuesday, June 02, 2009
7:48:43 AM
Hi Mike,
Nice article!
I have implemented your solution way in my project an i'm very happy for the solution.
But I need a solution for filtering the gridview?
When I try to use the objectdatasource1.filterExpression = String.Format("(NAME LIKE '{0}')", txtSearchByName.Text); I got a error meesage it's only possible when the Select method returns DataSet or DataTable.
Thank you once again
Spammer who tried to fake a comment for link bait
-
Friday, June 26, 2009
7:58:33 AM
I've been trying for over a month to get custom paging working with a gridview with no success, but I got yours working on my data quickly and easily. Thanks very much for the great article. The only addition I need is how to reduce the page numbers from being spread across the page when there is a large number of records returned, for example 1,2,3, 99,100, etc I would like 1-10... 11-20, etc. Can you please provide the code to do this?
Sim
-
Monday, October 18, 2010
10:50:09 AM
Exellent article. Thank you so much!!!
anjali
-
Friday, March 04, 2011
3:08:47 AM
Thanks a lot Mike you saved my time as i was searchign how to implement ,it is workign fine for me . i am using Gridview with List<Class> .
Anjali