1

For my current project we have a couple tables that need to be displayed/updated/inserted/deleted/etc. I'm using a GridView because it makes the most sense to me for the data involved. So I use LINQ to grab the data out of the DB. So far, very simple queries...GetAll and GetByID type stuff.
So my queries look like:

List<ds_Users_old> selectedUser = DataContext1.ds_Users_olds.ToList();

and

List<ds_Users_old> selectedUser = DataContext1.ds_Users_olds.Where(user => user.WorkEmail == email).ToList();

That sort of thing.

It's pretty easy for me to bind myUsers to a GridView and be done with it. Except that I also need to sort that GridView by any of the columns. SortExpression="FirstName", "LastName", "OfficePhone", "UserID", etc. myUsers.OrderByDescending(o => o.LastName).ToList(); works just fine but I need myUsers.OrderByDescending(o => SortExpression).ToList(); and that doesn’t work. And I don't want to make a different case for each SortExpression. From what I have gathered, making that dynamic can get really messy.

So my next thought was to turn my LINQ results into a DataTable in the DAL and just returning the DataTable instead of a generic list of my LINQ object. DataTables seem to be simpler to sort by dynamic fields. dt.DefaultView.Sort = e.SortExpression + " " + mySortDirection; and the like. But converting my LINQ results into a DataTable before using them seems a bit bulky to.

Below is a simplified version of my project:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            UsersGridView_BindGridViewData();
        }
    }

    protected void UsersGridView_BindGridViewData()
    {
        List<ds_Users_old>  allUsersList = UserClass.GetAllUsers();
        DataTable allUsersDT = UserClass.GetAllUsersDT();

        //UsersGridView.DataSource = allUsersList;
        //UsersGridView.DataBind();

        UsersGridView.DataSource = allUsersDT;
        UsersGridView.DataBind();
        Session["allUsersDT"] = allUsersDT;
    }

    protected void ComponentGridView_Sorting(object sender, GridViewSortEventArgs e)
    {
        DataTable dt = Session["testDT"] as DataTable;

        if (dt != null)
        {
            if (e.SortExpression == "GroupName")
                e.SortExpression = "GroupID";

            dt.DefaultView.Sort = e.SortExpression + " " + GetSortDirection(e.SortExpression);
            UsersGridView.DataSource = Session["allUsersDT"];
            UsersGridView.DataBind();
        }
    }

    private string GetSortDirection(string column)
    {
        string sortDirection = "ASC";
        string sortExpression = ViewState["SortExpression"] as string;

        if (sortExpression != null)
        {
            if (sortExpression == column)
            {
                string lastDirection = ViewState["SortDirection"] as string;
                if ((lastDirection != null) && (lastDirection == "ASC"))
                {
                    sortDirection = "DESC";
                }
            }
        }

        ViewState["SortDirection"] = sortDirection;
        ViewState["SortExpression"] = column;

        return sortDirection;
    }

And this is the class I access the data with:

public static class UserClass
{
    private static nsdc_supplyDataContext DataContext1 = new nsdc_supplyDataContext();

    #region SELECTS
    public static List<ds_Users_old> GetAllUsers()
    {
        List<ds_Users_old> selectedUser = DataContext1.ds_Users_olds.ToList();
        return selectedUser;
    }

    public static DataTable GetAllUsersDT()
    {
        List<ds_Users_old> selectedUser = DataContext1.ds_Users_olds.ToList();
        DataTable selectedUserDT = ConvertToDataTable(selectedUser);
        return selectedUserDT;
    }

    public static List<ds_Users_old> GetUsersByWorkEmail(string email)
    {
        List<ds_Users_old> selectedUser = DataContext1.ds_Users_olds.Where(user => user.WorkEmail == email).ToList();
        return selectedUser;
    }

    public static DataTable GetUsersByWorkEmailDT(string email)
    {
        List<ds_Users_old> selectedUsers = DataContext1.ds_Users_olds.Where(user => user.WorkEmail == email).ToList();
        DataTable selectedUsersDT = ConvertToDataTable(selectedUsers);
        return selectedUsersDT;
    }
    #endregion

    public static DataTable ConvertToDataTable<T>(IList<T> data)
    {
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        foreach (PropertyDescriptor prop in properties)
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
        foreach (T item in data)
        {
            DataRow row = table.NewRow();
            foreach (PropertyDescriptor prop in properties)
                row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
            table.Rows.Add(row);
        }
        return table;
    }
}

This just seems messy and feel there has to be a more elegant way of doing it.

1 Answer 1

1

Since you are using a list of objects as your data source, then you need to implement your own sorting logic, like this:

public sealed class GenericComparer<T> : IComparer<T>
{
    public enum SortOrder
    {
        Ascending = 0,
        Descending = 1
    }

    private string sortColumn;
    private SortOrder sortingOrder;

    public string SortColumn
    {
        get
        {
            return this.sortColumn;
        }
    }

    public SortOrder SortingOrder
    {
        get
        {
            return this.sortingOrder;
        }
    }

    public GenericComparer(string theSortColumn, SortOrder theSortingOrder)
    {
        this.sortColumn = theSortColumn;
        this.sortingOrder = theSortingOrder;
    }

    public int Compare(T x, T y)
    {
        PropertyInfo thePropertyInfo = typeof(T).GetProperty(this.sortColumn);
        IComparable object1 = (IComparable)thePropertyInfo.GetValue(x, null);
        IComparable object2 = (IComparable)thePropertyInfo.GetValue(y, null);
        if (this.sortingOrder == SortOrder.Ascending)
        {
            return object1.CompareTo(object2);
        }
        else
        {
            return object2.CompareTo(object1);
        }
    }
}

Now in your call to .Sort() method on your list of objects, you pass a new instance of this helper class (passing it the property of your list you want to sort by and the direction you want to sort - ascending or descending).

Since the comparer logic above uses generics, you can pass whatever type you want to sort by (i.e. int, DateTime, or even domain objects).

Sign up to request clarification or add additional context in comments.

2 Comments

That did the trick. Still seems like an awfully bulky solution for such a simple problem but it's the most elegant I've seen so far. Thanks.
@Jeremy - yeah, I wish there was a simpler solution too, but the good news is that you can re-use this as a utility class across your web application if you choose to do so. Glad it helped. Feel free to up-vote this answer as well. :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.