Feb 17, 2012

Anonymous Type LINQ Result and GridView Sorting in ASP.NET

It explains how to implement asp.net gridview sorting functionality when gridview datasource is Anonymous Type. Suppose you are using Entity Framework OR LINQ to sql, getting data with a particular structure having different columns from different tables (Anonymous Type) using LINQ and you have defined it as a datasource of gridview. It's okay to display data. Now, you have to implement sorting feature. One way is to convert Anonymous Type to Datatable and sort it defaultview, but it's too complex. You might have tasted dynamic sorting with extension method as mentioned here and here but not useful for Anonymous type. Another way is to use switch case for sortexpression and use OrderBy and OrderByDescending for each column. It's not a generalize solution. then what....???

Here is the solution.

GridView Structure:

Consider following gridview structure:


 <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" 
        AllowSorting="true" onsorting="GridView1_Sorting">
        <Columns>
            <asp:BoundField DataField="FirstName" HeaderText="First Name" SortExpression="FirstName"  /> 
            <asp:BoundField DataField="LastName" HeaderText="Last Name" SortExpression="LastName"  />
            <asp:BoundField DataField="Email" HeaderText="Email" SortExpression="Email"  />
            <asp:BoundField DataField="Total" HeaderText="Total Orders" SortExpression="Total"  />
        </Columns>
</asp:GridView>
gridview-sorting-aspdotnet-linq

Sorting Implementation:

1. You've to defined two properties for SortExpression and SortDirection.


 /// <summary>
    /// SortExpression of GridView
    /// </summary>
    public string GridViewSortExpression
    {
        get
        {
            return ViewState["GridViewSortExpression"] == null ? "FirstName" : ViewState["GridViewSortExpression"] as string;
        }
        set
        {
            ViewState["GridViewSortExpression"] = value;
        }
    }

    /// <summary>
    /// for Sorting Direction
    /// </summary>
    public SortDirection GridViewSortDirection
    {
        get
        {
            if (ViewState["sortDirection"] == null)
                ViewState["sortDirection"] = SortDirection.Ascending;

            return (SortDirection)ViewState["sortDirection"];
        }
        set { ViewState["sortDirection"] = value; }
    }

2. Set these properties values in gridview sorting event.


 protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
    {
        GridViewSortExpression = e.SortExpression;
        if (GridViewSortDirection == SortDirection.Ascending)
        {
            GridViewSortDirection = SortDirection.Descending;
        }
        else
        {
            GridViewSortDirection = SortDirection.Ascending;
        };
        BindGrid();        
    }

3. Get and Bind the Ordered data to gridview.

The tricky part to get property from GridViewSortExpression dynamically and define it in IEnumerable OrderBy method. See following to do it

----------------------------------------------

data.OrderBy(x =>x.GetType().GetProperty(GridViewSortExpression).GetValue(x, null));

----------------------------------------------

The complete method is :


void BindGrid() {
        using (SampleEntities context = new SampleEntities())
        {
            var data = (from cust in context.Customers
                        join order in context.Orders on cust.CustomerID equals order.CustomerID into OrdersbyCustomer                        
                        select new { FirstName = cust.FirstName, LastName = cust.LastName, Email = cust.Email, Total = OrdersbyCustomer.Count()}).ToList();
            if (data != null && data.Count > 0)
            {
                if (GridViewSortDirection == SortDirection.Ascending)
                {
                    GridView1.DataSource = data.OrderBy(x => x.GetType().GetProperty(GridViewSortExpression).GetValue(x, null));                  
                }
                else
                {
                    GridView1.DataSource = data.OrderByDescending(x => x.GetType().GetProperty(GridViewSortExpression).GetValue(x, null));                   
                };
            }
            else {
                GridView1.DataSource = null;
            }
            GridView1.DataBind();  
        }    
    }

Hope, It saves your time. Share your opinion or suggestion about it.