views:

300

answers:

4

Hi,

I need to sort a GridView (Not DataGridView, it's not the same thing) that is in need of a complex sort and I don't know how it can be done. I have two column, one containing a date and another containing a priority.

If the date is lesser or equal to today's date. I want to order by priority first, then by date. If the date is greater than today's date, I want to order by date first, then by priority.

Suppose totay is 2010-jan-13, some data ordered this way could look like these

   date       priority  Explanation
-----------   --------  --------------------------------------------
2010-jan-13      3      This comes first because it has the higer priority of all items whith a date <= today
2010-jan-12      2      Since this items and the next have the same priority they're ordered by date
2010-jan-13      2
2010-jan-14      5      This item and the followings have date > today, so they are ordered by date then by priority.
2010-jan-14      0
2010-jan-15      5
2010-jan-16      5

Is there anyway to sort a grid view mannually or by passing a compare functor?

edit : The datasource is a DataTable.

A: 

Sort procedure of dataGrinView uses Sort procedure of data source. To manually sort data create class that implements IBindingListView, implement it sort method like you want and use this class as DataSource in DataGridView

Orsol
A: 

Salut Mathieu,

Assuming you are using a DataSource and each element is a class (instead of say, a datarow), you could implement IComparable to your class. It adds the CompareTo method in which you decide how each element compares to each other.

class DatePriority: IComparable
{
    private DateTime date;
    public DateTime Date
    {
        get { return date; }
    }
    private int priority;
    public int Priority
    {
        get { return priority; }
    }

    public DatePriority(DateTime date, int priority)
    {
        this.date = date;
        this.priority = priority;
    }

    public int CompareTo(object obj)
    {
        if (obj is DatePriority)
        {
            DatePriority comparedDatePriority = obj as DatePriority;

            // Comparison logic
            // If the compared elements are today or before today, order by priority in descending order. Same priorities are ordered by date in ascending order
            // If the compared elements are for the future, order by date in ascending order. Same dates are order by priority in descending order
            if ((this.Date <= DateTime.Today && comparedDatePriority.Date <= DateTime.Today))
            {
                if (Priority == comparedDatePriority.Priority)
                    return Date.CompareTo(comparedDatePriority.Date);
                else
                    return -Priority.CompareTo(comparedDatePriority.Priority);
            }
            else
            {                    
                if (Date == comparedDatePriority.date)
                    return -Priority.CompareTo(comparedDatePriority.Priority); // Descending order
                else
                    return Date.CompareTo(comparedDatePriority.Date);
            }
        }
        throw new ArgumentException("Not a DatePriority");
    }
}    
Danny T.
+2  A: 

You need to sort your data source, not the GridView. (Tell us your data source and we can help. Is it a DataTable, SqlDataSource, business objects?)

From Sorting Data in a GridView Web Server Control at http://msdn.microsoft.com/en-us/library/hwf94875.aspx.

Custom Sorting

If the default sort behavior is not adequate for your requirements, you can customize the grid's sorting behavior. The basic technique for custom sorting is to handle the Sorting event. In the handler, you can do the following:

  • Customize the sort expression that is passed to the data source control. By default, the sort expression is the name of a single column. You can modify the sort expression in the event handler. For example, if you want to sort by two columns, you can create a sort expression that includes both. You can then pass the modified sort expression to the data source control. For more information, see the GridViewSortEventArgs..::.SortExpression property.

  • Create your own sorting logic. For example, if you are working with a data source that does not support sorting, you can perform the sort in your own code and then bind the grid to the sorted data.

Sort Example (Not Tested and Not Using LINQ [on purpose])

Dim oDataSet As DataSet = GatherDataSet()
Dim oDataTable As DataTable = oDataSet.Tables(0)
Dim oSort1 As New DataView(oDataTable, "Date > #2010/01/13#", "Date, Priority", DataViewRowState.CurrentRows)
Dim oSort2 As New DataView(oDataTable, "Date <= #2010/01/13#", "Priority, Date", DataViewRowState.CurrentRows)
Dim oGridDataTable As DataTable
oGridDataTable = oSort1.ToTable
oGridDataTable.Merge(oSort2.ToTable)

oGridView.DataSource = oGridDataTable

'...
'you can then merge any changes back into the data set, if needed
oDataSet.Merge(oGridDataTable)
AMissico
@AMissico, the DataSource is a table, is there anyway to manually sort a DataTable?
Mathieu Pagé
@AMissico, thanks that will certainly solve my problem. I've accepted this answer.
Mathieu Pagé
A: 

Yes, You can do it. Here's how you do that.

Assuming you have a GridView which calls for records from a BusinessLayer method. I will take example of UserManager as business-layer proxy class.

    [DataObjectAttribute()]
    public static class UserManager
    {
        [DataObjectMethod(DataObjectMethodType.Select, true)]
        public static UserCollection GetUsers()
        {
            return UserDB.GetAll();
        }

        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public static UserCollection GetUsers(string sortExpression)
        {
            UserCollection users = UserDB.GetAll();
            users.Sort(new EntityComparer<User>(sortExpression));
            return users;
        }
    }

Look at this line of code in over-loaded GetUsers method.

users.Sort(new EntityComparer<User>(sortExpression));

I have written a Generic Comparer implementation for my business objects. EntityComparer is just a generic class that implements IComparer interface. You can write your own Comparer implementation [that implements IComparer interface] and call it as the code above.

Here's how my GridView looks like..

         <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
            DataSourceID="ObjectDataSource1">
            <Columns>
                <asp:BoundField DataField="Id" HeaderText="Id" SortExpression="Id" />
                <asp:BoundField DataField="UserName" HeaderText="UserName" 
                    SortExpression="UserName" />
                <asp:BoundField DataField="Password" HeaderText="Password" 
                    SortExpression="Password" />
                <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
                <asp:BoundField DataField="Email" HeaderText="Email" SortExpression="Email" />
                <asp:BoundField DataField="CompanyName" HeaderText="CompanyName" 
                    SortExpression="CompanyName" />
            </Columns>
        </asp:GridView>
        <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" 
            OldValuesParameterFormatString="original_{0}" SelectMethod="GetUsers" 
            TypeName="FilePark.BusinessLayer.UserManager"></asp:ObjectDataSource>

Also note that GridView will pass the sortExpression upon postback and call the overloaded method.

this. __curious_geek