I don’t know why everyone forgets about using hidden fields! They are so "cheaper" that ViewState (which I turned off since 2005). If you do not want to use Session or ViewState, then here is my solution:
Put these two hidden fields on your aspx page and put the default collation for your data (for example, I use LastName):
<asp:HiddenField ID="hfSortExpression" runat="server" Value="LastName" /> <asp:HiddenField ID="hfSortDirection" runat="server" Value="Ascending" />
Then put this helper code on your base page (you have a base page, right? If not, enter the .cs code behind).
/// <summary> /// Since native ASP.Net GridViews do not provide accurate SortDirections, /// we must save a hidden field with previous sort Direction and Expression. /// Put these two hidden fields on page and call this method in grid sorting event /// </summary> /// <param name="hfSortExpression">The hidden field on page that has the PREVIOUS column that is sorted on</param> /// <param name="hfSortDirection">The hidden field on page that has the PREVIOUS sort direction</param> protected SortDirection GetSortDirection(GridViewSortEventArgs e, HiddenField hfSortExpression, HiddenField hfSortDirection) { //assume Ascending always by default!! SortDirection sortDirection = SortDirection.Ascending; //see what previous column (if any) was sorted on string previousSortExpression = hfSortExpression.Value; //see what previous sort direction was used SortDirection previousSortDirection = !string.IsNullOrEmpty(hfSortDirection.Value) ? ((SortDirection)Enum.Parse(typeof(SortDirection), hfSortDirection.Value)) : SortDirection.Ascending; //check if we are now sorting on same column if (e.SortExpression == previousSortExpression) { //check if previous direction was ascending if (previousSortDirection == SortDirection.Ascending) { //since column name matches but direction doesn't, sortDirection = SortDirection.Descending; } } // save them back so you know for next time hfSortExpression.Value = e.SortExpression; hfSortDirection.Value = sortDirection.ToString(); return sortDirection; }
Then you need to handle the sort in the grid sort event handler. Call the method above from the sort event handler before calling your main method, which receives your data.
protected void gridContacts_Sorting(object sender, GridViewSortEventArgs e) {
Since so many examples use DataTables or DataViews or other collections other than LINQ, I thought I would include an example of calling a mid-level method that returns a general list, and use LINQ to sort in order to round the example and make it a more “real world”:
private void GetCases(AccountID accountId, string sortExpression, SortDirection sortDirection) {
Finally, here is a downward and dirty sort that uses LINQ in the general list of user objects. I'm sure there is something more exciting that the trick will do, but this illustrates the concept:
closed static Sort list (line sortExpression, SortDirection sortDirection, list pendingCases) {
switch (sortExpression) { case "FirstName": pendingCases = sortDirection == SortDirection.Ascending ? pendingCases.OrderBy(c => c.FirstName).ToList() : pendingCases.OrderByDescending(c => c.FirstName).ToList(); break; case "LastName": pendingCases = sortDirection == SortDirection.Ascending ? pendingCases.OrderBy(c => c.LastName).ToList() : pendingCases.OrderByDescending(c => c.LastName).ToList(); break; case "Title": pendingCases = sortDirection == SortDirection.Ascending ? pendingCases.OrderBy(c => c.Title).ToList() : pendingCases.OrderByDescending(c => c.Title).ToList(); break; case "AccountName": pendingCases = sortDirection == SortDirection.Ascending ? pendingCases.OrderBy(c => c.AccountName).ToList() : pendingCases.OrderByDescending(c => c.AccountName).ToList(); break; case "CreatedByEmail": pendingCases = sortDirection == SortDirection.Ascending ? pendingCases.OrderBy(c => c.CreatedByEmail).ToList() : pendingCases.OrderByDescending(c => c.CreatedByEmail).ToList(); break; default: break; } return pendingCases; }
And last but not least (have I already said that?), You might want to add something like this to your Page_Load handler, so that the grid is bound by default when the page loads ... Please note that _accountId is a querystring parameter, converted to the native type AccountID of mine in this case ...
if (!Page.IsPostBack) { //sort by LastName ascending by default GetCases(_accountId,hfSortExpression.Value,SortDirection.Ascending); }