SingingEels : Development Community & Resource

Login

Articles

  • ADO.NET (2)
  • ASP.NET (36)
  • Azure (0)
  • LINQ (5)
  • Security (2)
  • Silverlight (3)
  • SQL (7)
  • Standards (5)
  • WCF (2)

Syndication

  • Articles RSS
  • Blogs RSS

Contribute

  • Our Authors List
  • Member Sign-Up
  • Suggestions Box

Self Sorting GridView with LINQ Expression Trees

(Apr 18 2008 - 11:21:04 PM by Timothy Khouri) - [print article]

The GridView control in ASP.NET 2.0 is lacking some major (yet common) functionality - sorting. This article will show you how to create a "self-sorting" GridView using LINQ expression trees.

First, it's important to explain what I mean when I say that the GridView doesn't have sorting capabilities. You're probably saying to yourself - "I know the GridView has sorting built in because it has a 'Sort' method and 'Sorting' and 'Sorted' events." And that's true, but those are merely placeholders that allow you to write your own sorting code.

Also, if you use the designer to build your GridViews, and bind them to SQL data sources, then you might also be confused about the above statements. But rest assured that the sorting magic is all happening in the terribly inefficient SqlDataSource control, and not the actual GridView itself.

If you're not already familiar with the basics of LINQ, then you might want to first read this article: Learn The Basics of LINQ. To sum up LINQ in one sentence (for the purpose of moving on) I would say: "LINQ is a language feature in .NET that provides a ton of out-of-the-box functionality for querying data."

The Problem - Why The GridView Can't Sort

So why is it that the GridView control doesn't have the ability to sort by default? The problem lies in the fact that the data source is very dynamic, could be of any type and could even be just a paged subset of the ultimate source.

Another problem is performance. If your data source was from a SQL table, then you would want to pass the sorting functionality on to the SQL Server itself to gain the most performance. Because the GridView doesn't know what your source will be, it can't really provide the needed functionality.

The Solution - LINQ

Since LINQ provides querying capabilities on a generic level, the above problems are no problem. Because LINQ to objects can handle *any* enumerable objects, and LINQ to SQL is smart enough to pass the sorting logic on to SQL Server, you win no matter what.

For example, imagine if the data source was a collection of MembershipUsers (via the Membership.GetUsers method). Here's how easy it would be to sort using LINQ and the OrderBy method:

// Using LINQ to sort by a user's name.
myGridView.DataSource = Membership.GetUsers()
   .OfType<MembershipUser>()
   .OrderBy(user => user.Name);

That was very easy to do, but that's because we know the data type of our source at compile time. But if we are going to make a generic "self sorting GridView", then we have to build our functionality with the limitation of not knowing the data type of the data source or the name of the field that is being sorted. So we'll need to reconstruct this functionality at runtime by building "expression trees" (the power behind LINQ).

Step One - Build Our GridView Control

To begin with, let's build a basic control that inherits from GridView , and stub out a placeholder to put our sorting logic.

public class SelfSortingGridView : GridView
{
   protected override void OnSorting(GridViewSortEventArgs e)
   {
       // Our code below is going to live here...

   }
}

Now that we have our custom GridView control ready to go, we can move on to step two.

Step Two - Creating an Expression to Sort With

As was stated earlier, we need to build an expression that will tell LINQ how we want to sort our data source. There are a few tricky issues here that we need to identify and overcome. If we try to copy the example found in this blog post to reproduce our sorting example at the top of this article, we would get half-way there:

// Using a custom LINQ expression to sort by a user's name.
var param = Expression.Parameter(typeof(MembershipUser), "user");

// By the way, if you don't "box" the return type into an object,

// you'll get a runtime error when you try to sort by a value type.

// So instead of doing this (which would be expected):

var sortExpression = Expression.Lambda<Func<MembershipUser, object>
   (Expression.Property(param, "Name"), param);

// I'm going to do this:

var sortExpression = Expression.Lambda<Func<MembershipUser, object>
   (Expression.Convert(Expression.Property(param, "Name"), typeof(object)), param);

// And then I can sort my data source:

myGridView.DataSource = Membership.GetUsers()
   .OfType<MembershipUser>().OrderBy(sortExpression);

So we've solved one issue - that of finding the property to sort with by it's name. The "Expression.Property" method above did that for us. Now, we have to solve the second issue - not knowing what the data type of the data source will be until runtime. To solve this in the fewest lines of code, I'm going to make a custom generic class that will create the sort expression for us so that we can simply supply the type at runtime.

public class GenericSorter<T>
{
   public IEnumerable<T> Sort(IEnumerable<T> source, string sortBy)
   {
       var param = Expression.Parameter(typeof(T), "item");

       var sortExpression = Expression.Lambda<Func<T, object>>
           (Expression.Convert(Expression.Property(param, sortBy), typeof(object)), param);

       return source.AsQueryable<T>().OrderBy<T, object>(sortExpression);
   }
}

Beautiful! Notice that because we are using a generic class, we can tell the compiler that we want to use the type "T" (whatever "T" will be at runtime, we don't care)! So, if I wanted to create an instance of my GenericSorter class at runtime, passing in a type that I won't know until runtime, and then call the "Sort" method, I would just do some simple reflection as will be shown below.

For simplicities sake, the data source is stored in a variable called "_data". You can download the whole source code at the end of the article to see exactly how it's done. Here's a sample of the code:

// Give me the data type of the GridView's data source.
Type dataSourceType = _data.GetType();

// Determine the data type of the items in the data source at runtime.

Type dataItemType = typeof(object);

if (dataSourceType.HasElementType)
{
   // Get the element type if the data source is an array.

   dataItemType = dataSourceType.GetElementType();
}
else if (dataSourceType.IsGenericType)
{
   // Get the element type if the data source is a generic list.

   dataItemType = dataSourceType.GetGenericArguments()[0];
}

// Create an instance of the GenericSorter class passing in the data item type.

Type sorterType = typeof(GenericSorter<>).MakeGenericType(dataItemType);

var sorterObject = Activator.CreateInstance(sorterType);

// Now I can call the "Sort" method passing in my runtime types.

this.DataSource = sorterType.GetMethod("Sort", new Type[] { dataSourceType, typeof(string) })
   .Invoke(sorterObject, new object[] { _data, e.SortExpression });

this.DataBind();

Conclusion

At first glance, it may seem like we're doing a lot of code just for sorting functionality. You may even be thinking that this is an extremely convoluted way of sorting a GridView, but really it's not. Once you understand what LINQ is doing, and how to build your own expression trees, you'll really appreciate this new language feature in .NET.

I'll include a web project that has the full source code and some examples of different objects that can be sorted here. If you first don't understand what all is going on, I'd recommend that you download the source code and step through it in the debugger.

I hope this article has excited you about LINQ and expression trees. If you're not excited, I hope your informed. If you don't feel informed, I hope at least that you're not now afraid of LINQ.

Here's the source code and sample project: SingingEels_LinqSelfSortingGridView.zip

Update: Jun 04 2008

I've updated the source code to include the fix that was made due to the comments below.

Update: Sep 18 2008

Even more updated due to a request in a comment below. I've added a "LateBoundSorter" class so that the SelfSortingGridView has the ability to sort *ANY* enumeration. Even if you sent in a List<object> as the source. The reason why this was not doable before was due to reflection not finding the property named "FirstName" (for example) on the "System.Object" type.

What the LateBoundSorter does (as a last resort) is it gets the value from the object in the enumeration itself, instead of relying on the type of the list. Meaning, if you have a List<object>, but the items in the list are "Person" objects, then the LateBoundSorter will reflect the "FirstName" property from the "Person" type.

Here's the latest build: SingingEels_LinqSelfSortingGridView_updated20080918.zip

Update: Feb 27 2009

Due to popular request... I've updated the project to take "sort direction" into account. Here's the code that was added to the "SelfSortingGridView_Sorting" method at the top:

if (e.SortExpression == this._lastAscendingSort)
{
   this._lastAscendingSort = null;

   e.SortDirection = SortDirection.Descending;
}
else
{
   this._lastAscendingSort = e.SortExpression;
}

And then in the "GenericSorter" I simply check for the sort-direction and call "OrderBy" or "OrderByDescending" respectively.

Here's the newly updated project with full sorting: SingingEels_LinqSelfSortingGridView_updated20090227.zip

  • Apr 22 2008 - 02:12:46 PM tommy

    Thank you for this great article!

    The thing is, that I can't get it working if I set the datasource to:

    var customers = from c in dc.GetTable<Customer>()

    orderby c.Name

    select c;

    myGridView.DataSource = customers;

    myGridView.DataBind();

    Yes, LINQ to SQL.

    I get the following error:

    Exception Details: System.InvalidOperationException: Cannot order by type 'System.Object'.

    Any ideas, or am I missing something here?

    Thanks in advance.

  • May 18 2008 - 08:13:16 AM Marian

    Nice article,

    but I have the same problem as tommy with linq to sql as datasource.

    Any idea?

    Thanks

  • Jun 04 2008 - 03:32:53 PM Timothy Khouri

    Hey guys,

    I found the problem you are having with LINQ to SQL. It's basically complaining because I just said "we'll pass you an 'object' to sort by." I was cutting a corner there, which works with LINQ to Objects, but not L2S.

    So, the fix is easy... I've added a new parameter to my "GenericSorter" class. Now it takes the type "T" and the type of the field being sorted, "PT". This works with LINQ to SQL, and LINQ to Objects.

    I'll be updating the project in a few minutes, and I'll add a note to the article.

    Thanks,

    -Timothy

  • Jul 09 2008 - 06:22:10 AM mikewebthree

    Hi,

    Great article, this has helped me loads. Got it working in my own implentation.

    I have hit a problem though and I'm not sure how to solve it. One of the columns in my grid is a templatefield that shows a string from a parent row, so I'm using Databinder.Eval to display it. It displays fine but on clicking sort it breaks, in debug I can see that it throws when we execute "var fieldType = dataItemType.GetProperty(e.SortExpression);", fieldType is null.

    Any help would be much appreciated..

  • Jul 09 2008 - 02:32:44 PM Timothy Khouri

    Hey Mike,

    That's a great question, but unfortunately it's not quite solvable for your scenario. The reason is that there is no actual property for that template field, but instead it's dynamic (which is the very reason for using the template field).

    The self-sorting grid view isn't sorting on values *after* being databound, but rather it's sorting on the source (which is what makes it so cool). Is there a way that you could modify your source (whether in LINQ, or SQL) to calculate that value before being assigned, and then get rid of the template field)?

    Thanks,

    -Timothy

  • Jul 29 2008 - 01:18:33 PM aldousd666

    This has to be one of the most useful posts I've hit in a while. Good stuff. I'm so enamored of linq's delayed tree evaluation (and of course it's sub-sequent database-server-side SQL expression of the same) and this just about completes the circle. Also should check out the http://www.albahari.com/nutshell/predicatebuilder.html for more goodies like it. I just can't get over how incredibly useful all this LINQ jazz is. (I was convinced it was going to be all hype when it first dropped in CTP's)

  • Jul 29 2008 - 03:36:02 PM freeborn5

    I see that using LINQ is a good way to query data but when the Gridview control is not working there is an alternative to going through all this. I have resorted to allowing my class which is LINQed up to return a good old data table.

    Here is an example of my class

    [System.ComponentModel.DataObjectMethod(System.ComponentModel.DataObjectMethodType.Select)]

    public static DataTable GetSubjectListForGroup(int GroupID)

    {

    DataTable table = new DataTable();

    table.Columns.Add("ApplicationId");

    table.Columns.Add("ApplicationName");

    DataRow dr = table.NewRow();

    dr["ApplicationId"] = "0";

    dr["ApplicationName"] = "";

    table.Rows.Add(dr);

    var res2 = from a in DataContext.tblApplications

    where a.ActiveStart < DateTime.Now & a.ActiveEnd > DateTime.Now

    select a;

    foreach (tblApplication Ap in res2)

    {

    dr = table.NewRow();

    dr["ApplicationId"] = Ap.ApplicationId.ToString();

    dr["ApplicationName"] = Ap.ApplicationName;

    table.Rows.Add(dr);

    }

    return table;

    }

  • Aug 11 2008 - 03:41:43 PM rmmason

    Great article!

    I think I have either found a bug or don't understand how the page life cycle effects the gridview. When I tried to use your class in my project it appeared not to be working so I created a separate test page and it worked fine. From stepping through the code the problem is that on the solution where it does not work I set the data source of my gridview in the method for a button click and then when sort is called dataView is null. If I move the code that sets the datasource to Page_Load it works fine.

    Is this as expected and if so why?

  • Aug 11 2008 - 06:11:27 PM Timothy Khouri

    The answer is very simple, and yes, it's because of the page life-cycle. If you'll remember all control events (such as Button_Click, DropDownList_SelectedIndexChanged, Grid_Sorting, etc) happen *after* Page_Load. Also, they have to be wired up at the latest on PageLoadCompleted.

    So, the problem is that since I'm tapping into the "OnSorting" method up there, and you're calling it too late (in the Button_Click), the timing is off.

    You could maybe add a "ReSort()" method to the grid, and call it in your button click. Or you can just change the timing of the sorting.

    Thanks,

    -Timothy Khouri

  • Aug 14 2008 - 12:50:31 PM rmmason

    Hi Timothy,

    Thanks for your reply earlier. I have been playing with your code and been trying to implement paging but that seemed to be a non starter from within the gridview because I was getting an error saying the datasource does not support paging.

    What I was really after was a datasource that supported IQueryable anyway so I started down the road of creating a custom DataSource component using portions of your code. I thought since your code was the inspiration it would be nice to share it back.

    At the minute the code appears to work just fine however when using profiler I have found that the skip and next linq operators are not being translated into ... ROW_NUMBER() ... when executing on the database. I have not managed to solve this yet but if I do I will post again. In the mean time here is the code and if you can see the problem please do let me know.

    using System;

    using System.Data;

    using System.Configuration;

    using System.Linq;

    using System.Web;

    using System.Web.Security;

    using System.Web.UI;

    using System.Web.UI.HtmlControls;

    using System.Web.UI.WebControls;

    using System.Web.UI.WebControls.WebParts;

    using System.Xml.Linq;

    using System.Collections;

    using System.Collections.Generic;

    using System.Linq.Expressions;

    using System.Reflection;

    /// <summary>

    /// Summary description for LinqQueryDataSource

    /// </summary>

    ///

    namespace Inflecto.Web.UI.WebControls

    {

    public class LinqQueryDataSource : DataSourceControl

    {

    private LinqQueryDataSourceView view;

    private IQueryable query;

    public IQueryable LinqQuery

    {

    get {return query;}

    set {query = value;}

    }

    public LinqQueryDataSource() : base() { }

    protected override DataSourceView GetView(string viewName)

    {

    // We only have one view... If it has not been created then create it else return

    if (view == null)

    view = new LinqQueryDataSourceView(this, string.Empty, query);

    return view;

    }

    protected override ICollection GetViewNames() {

    ArrayList al = new ArrayList(1);

    al.Add(LinqQueryDataSourceView.DefaultViewName);

    return al as ICollection;

    }

    public class LinqQueryDataSourceView : DataSourceView

    {

    IQueryable originalQuery;

    string previousSortExpression;

    public static string DefaultViewName = "LinqQueryView";

    public LinqQueryDataSourceView(IDataSource owner, string name, IQueryable query)

    : base(owner, DefaultViewName)

    {

    originalQuery = query;

    previousSortExpression = string.Empty;

    }

    public override bool CanPage

    {

    get {return true;}

    }

    public override bool CanSort

    {

    get{return true;}

    }

    public override bool CanRetrieveTotalRowCount

    {

    get{return true;}

    }

    protected override IEnumerable ExecuteSelect(DataSourceSelectArguments arguments)

    {

    if (originalQuery == null)

    {

    throw new Exception("LinqQueryDataSource must have LinqQuery set");

    }

    // Grab types needed for reflection

    IQueryable thisQuery = originalQuery;

    Type dataSourceType = thisQuery.GetType();

    Type dataItemType = getDataItemType(thisQuery, dataSourceType);

    // Set total Row Count Property

    if (arguments.RetrieveTotalRowCount)

    arguments.TotalRowCount = getTotalRowCount(thisQuery, dataItemType, dataSourceType);

    // If sorting requested perform this and get deferred query back

    if (arguments.SortExpression != string.Empty)

    thisQuery = performSort(thisQuery, arguments.SortExpression, dataSourceType, dataItemType);

    // If Paging requested perform paging

    if (arguments.MaximumRows !=0)

    thisQuery = performPaging(thisQuery, arguments.StartRowIndex, arguments.MaximumRows,

    dataItemType, dataSourceType);

    // Convert IQueryable to list as we need something that implements ICollection

    // to stop the gridview whineing

    Type listCasterType = typeof(GenericListCaster<>).MakeGenericType(dataItemType);

    object listCasterObject = Activator.CreateInstance(listCasterType);

    return (IEnumerable) listCasterType.GetMethod("ToList", new Type[] { dataSourceType})

    .Invoke(listCasterObject, new object[] { thisQuery });

    }

    private IQueryable performSort(IQueryable thisQuery, string sortExpression, Type dataSourceType, Type dataItemType)

    {

    SortDirection sortDirection;

    if (sortExpression.EndsWith(" DESC"))

    {

    sortDirection = SortDirection.Descending;

    sortExpression = sortExpression.Substring(0, sortExpression.IndexOf(" DESC"));

    }

    else

    {

    sortDirection = SortDirection.Ascending;

    }

    object sorterObject = null;

    Type sorterType = null;

    PropertyInfo property = dataItemType.GetProperty(sortExpression);

    sorterType = typeof(GenericSorter<,>).MakeGenericType(dataItemType, property.PropertyType);

    sorterObject = Activator.CreateInstance(sorterType);

    return (IQueryable)sorterType.GetMethod("Sort", new Type[] { dataSourceType, typeof(string), typeof(SortDirection) })

    .Invoke(sorterObject, new object[] { thisQuery, sortExpression, sortDirection });

    }

    private IQueryable performPaging(IQueryable thisQuery, int startRowIndex, int maximumRows, Type dataItemType, Type dataSourceType)

    {

    Type pagerType = typeof(GenericPager<>).MakeGenericType(dataItemType);

    object pagerObject = Activator.CreateInstance(pagerType);

    return (IQueryable)pagerType.GetMethod("Page", new Type[] { dataSourceType, typeof(int), typeof(int) })

    .Invoke(pagerObject, new object[] { thisQuery, startRowIndex, maximumRows });

    }

    private Type getDataItemType(IEnumerable dataSource, Type dataSourceType)

    {

    Type dataItemType = typeof(object);

    if (dataSourceType.HasElementType)

    {

    dataItemType = dataSourceType.GetElementType();

    }

    else if (dataSourceType.IsGenericType)

    {

    dataItemType = dataSourceType.GetGenericArguments()[0];

    }

    else if (dataSource is IEnumerable)

    {

    IEnumerator dataEnumerator = dataSource.GetEnumerator();

    if (dataEnumerator.MoveNext() && dataEnumerator.Current != null)

    {

    dataItemType = dataEnumerator.Current.GetType();

    }

    }

    return dataItemType;

    }

    private int getTotalRowCount(IQueryable thisQuery, Type dataItemType, Type dataSourceType)

    {

    Type rowCounterType = typeof(GenericRowCounter<>).MakeGenericType(dataItemType);

    object rowCounterObject = Activator.CreateInstance(rowCounterType);

    return (int)rowCounterType.GetMethod("CountRows", new Type[] { dataSourceType })

    .Invoke(rowCounterObject, new object[] { thisQuery });

    }

    }

    }

    public class GenericListCaster<T>

    {

    public List<T> ToList(IQueryable source)

    {

    return source.OfType<T>().AsQueryable<T>().ToList();

    }

    }

    public class GenericRowCounter<T>

    {

    public int CountRows(IQueryable source)

    {

    return source.OfType<T>().AsQueryable<T>().Count<T>();

    }

    }

    public class GenericPager<T>

    {

    public IEnumerable<T> Page(IEnumerable source, int pageIndex, int pageSize)

    {

    return source.OfType<T>().AsQueryable<T>().Skip<T>(pageIndex).Take<T>(pageSize);

    }

    }

    public class GenericSorter<T, PT>

    {

    public IEnumerable<T> Sort(IEnumerable source, string sortExpression, SortDirection sortDirection)

    {

    var param = Expression.Parameter(typeof(T), "item");

    var sortLambda = Expression.Lambda<Func<T, PT>>(Expression.Convert(Expression.Property(param, sortExpression), typeof(PT)), param);

    if (sortDirection == SortDirection.Descending)

    {

    return source.OfType<T>().AsQueryable<T>().OrderByDescending<T, PT>(sortLambda);

    }

    else

    {

    return source.OfType<T>().AsQueryable<T>().OrderBy<T, PT>(sortLambda);

    }

    }

    public IEnumerable<T> Sort(IEnumerable<T> source, string sortExpression, SortDirection sortDirection)

    {

    var param = Expression.Parameter(typeof(T), "item");

    var sortLambda = Expression.Lambda<Func<T, PT>>(Expression.Convert(Expression.Property(param, sortExpression), typeof(PT)), param);

    if (sortDirection == SortDirection.Descending)

    {

    return source.AsQueryable<T>().OrderByDescending<T, PT>(sortLambda);

    }

    else

    {

    return source.AsQueryable<T>().OrderBy<T, PT>(sortLambda);

    }

    }

    }

    }

  • Aug 15 2008 - 07:48:02 AM rmmason

    Timothy,

    In reply to my previous post. The error with the code is due to the fact I am passing the LINQ query into the generic paging and sorting methods as IEnumerable. Changing this to IQueryable fixes the issues and I now have a datasource that is both pagable and sortable in both directions.

    Many thanks for providing the inspiration ...

  • Aug 15 2008 - 06:28:04 PM Timothy Khouri

    Great and very glad to hear it! I've run into the same issue with the "IEnumerable" vs "IQueryable"... good work :)

  • Sep 17 2008 - 03:23:26 PM Rhoam

    This is a truly elegant and flexible solution. By far the best implementation of a sortable GridView I have encountered.

    When assigning a List<object> or ArrayList as the DataSource, the sort mechanism fails to pass either type through as an IEnumerable object. Specifically, it failes to pass this point:

    if (_data == null) { return; }

    I realize I am probably missing something painfully obvious but it seems to me that a List and ArrayList both use IEnumerable and should be handled appropriately. This would be a massive improvement on two of my application and I would really appreciate any help.

    Rhoam

  • Sep 17 2008 - 07:04:23 PM Timothy Khouri

    Hey Rhoam,

    I tried the ArrayList and filled mine with a few "Person" objects and it worked fine. But, when I tried the List<object>, it crashed (and I know why). It's because the base type "object" doesn't have a "FirstName" property to sort on. So, I'm working on a fix that will do a 'last minute eval' in such cases :)

    I'll try to post the new project in the morning if I remember!

    Thanks,

    -Timothy

  • Sep 18 2008 - 08:51:31 AM Rhoam

    That is very interesting. It looks to be completely agnostic of the underlying elements. One of my applications contains names, work order numbers, dollar values, etc. The code you've presented appears to be able to sort on any of these items.

    Rhoam

  • Sep 19 2008 - 03:01:50 PM Rhoam

    Pardon me, but I beleive I gave you some false information. Previously I specified a List<object> but I was intending to use object in a generic way and I hope you understood it that way. Really my list is no different than your List<Person> only mine is List<JobData> (which contains elements such as JobNumber, JobTitle, JobCost, etc). I've tried converting the data into a DataTable and an array (using ToArray) but it always comes up the same.

    What am I missing?

    Rhoam

  • Sep 22 2008 - 01:19:27 PM Rhoam

    OK, that was just pathetic. The code works as advertised. The problem was that since I am retrofitting the applications I was trying to just change the grid. Unfortunately, the DataSource was always coming up empty because the original application did not save or restore data from the viewstate.

    As I said, pathetic.

    Rhoam

  • Sep 23 2008 - 08:33:55 AM Rhoam

    I didn't see how you were implementing a descending sort, so I implemented one by giving the grid a couple of properties and extending the code a tiny bit by passing the sort direction to the GenericSorter.Sort class.

    if(sortDirection == SortDirection.Ascending)

    return source.AsQueryable<T>().OrderBy<T, PT>(_Lambda);

    else

    return source.AsQueryable<T>().OrderByDescending<T, PT>(_Lambda);

  • Nov 25 2008 - 05:01:46 AM trekmp

    Just found this articale and it has sorted out a problem I'd been having for a while. Not been doing .NET all that long so this helped me greatly.

    A note to Rhoam, you managed to get the sort in descending order working, any chance you could expand a little on what you did with regards to giving the grid a couple of properties, etc. I've added the above code but no idea how to make use of it :(

  • Feb 26 2009 - 07:32:45 AM Robb

    Yes, Rhoam, can you please elaborate as to how you got the bi-directional sort to work. I get the error 'sortdirection is a type but is used like a variable' when I use your code posted above.

  • Feb 27 2009 - 06:26:56 AM Timothy Khouri

    All - I've added "Sort Direction" code at the end of the article, and I'm also including an updated project source. Now sorting Ascending and Descending happens naturally.

  • Mar 25 2009 - 05:17:40 PM kiwipete

    Hi

    Nice control.

    I've updated it to also handle paging.

    Blog didn't let me upload the full code so I posted it to:

    http://www.singingeels.com/Blogs/kiwipete/2009/03/25/Follow_up_to_Self_Sorting_GridView.aspx

  • Mar 25 2009 - 05:18:36 PM kiwipete

    Hi

    Nice control.

    I've updated it to also handle paging.

    Blog didn't let me upload the full code so I posted it to a separate blog post.

    Follow_up_to_Self_Sorting_GridView

  • Apr 29 2009 - 11:03:20 PM brintf

    I was getting an error when I would set the GridView to allow paging. I'm binding with the List<T>, so I realized that the problem is that each of the Sort methods in the GenericSorter and LateBoundSorter return IEnumerable<T>. I modified those methods to return a List<T>, by adding the .ToList() at the end of each return statement and now it works great. Thanks for the example.

  • May 11 2009 - 01:01:35 AM sycho

    I have a little problem with this. Here is the blog cause I have to many lines:

    http://www.singingeels.com/Blogs/sycho/2009/05/11/Problem_with_self_sorting_gridview.aspx

You must be logged in to add comments. If you have not already done so, you can create an account here. If you already are a member, you first need to login before you can comment.

Developer / Architect / Author

Check Out Dev++

Test your development skills, give proof to recruiters and employers at dev++

Related Blogs

These are the most recent blog posts related to this article.

  • Aspose.Newsletter February 2012 Edition is out Now
  • Embed Videos inside PowerPoint Presentation & Stable PDF Generation
  • Excel to PDF Conversion, XLS, XLSX & ODS Rendering are Improved
  • Convert SVG to Pdf & Render Pdf into Image with Desired Dimensions
  • Add Optical Character Recognition in Java Web & Desktop Applications

Related Ads

SingingEels.com as of Feb 03 2012 - 11:53:36 PM - (0.1249992)