Marwan مروان
Marwan مروان

Reputation: 2221

How to Group and Sort Objects in ObjectListView?

I am trying to group my list of objects in an ObjectListView.

The ObjectListView should group the objects based on the first column but then have that same column sorted based on a custom sort.

How do I do that? I have read through the documentation for ObjectListView: http://objectlistview.sourceforge.net/cs/gettingStarted.html#gettingstarted

So far, I have implemented my custom sort but I am not sure how to trigger the grouping? Remember that I am trying to group on the first column but then apply a custom sort.

My custom sort relis on the BeforeSorting event:

// after initializing components
olv.BeforeSorting += olv_BeforeSorting;

Then...

private void olv_BeforeSorting(object sender,BrightIdeasSoftware.BeforeSortingEventArgs e)
{
        olvDataSource.Sort((x, y) => x.Group.ID.CompareTo(y.Group.ID));
        e.Handled = true;
}

The ObjectListView displays my ordered object list but it is not grouped together. Each object displays on its own row without a group heading.

How do I group my objects after sorting them?

Upvotes: 2

Views: 2541

Answers (3)

user1169420
user1169420

Reputation: 830

This works and is basically what is described in the cookbook here http://objectlistview.sourceforge.net/cs/recipes.html?highlight=sort#how-can-i-change-the-ordering-of-groups-or-rows-within-a-group

First subscribe to the olv BeforeCreatingGroups event.

Then create a custom sort comparator in the event handler. In this case for a group matching "Turtles" it will push to the end of the sort, but you can obviously have however much convoluted logic you want in there.

private void Olv_BeforeCreatingGroups(object sender, CreateGroupsEventArgs e)
{
    e.Parameters.GroupComparer = Comparer<BrightIdeasSoftware.OLVGroup>.Create(
        (x, y) => (
            x.Header == "Turtles" ? 1
                : x.GroupId.CompareTo(y.GroupId)
        )
    );
}

This is what I used initially since it's what was in the cookbook. But I ended up switching to something more like Marwan's answer because that one creates a space to reconfigure the group headers themselves.

Upvotes: 2

Marwan مروان
Marwan مروان

Reputation: 2221

I am sharing this for anyone that might come across here looking for a way to apply a custom sort on groups within an ObjectListView.

There might be better ways to do this, but this way worked for me.

colFirst.GroupFormatter = (BrightIdeasSoftware.OLVGroup group, BrightIdeasSoftware.GroupingParameters parms) =>
{
    ObjectA a = (OjectA)group.Key;

    /* Add any processing code that you need */

    group.Task = " . . . ";
    group.Header = "Special Name: " + a.Name;
    group.Subtitle = $("Object A: {a.Index}, Total Water Consumption: {a.WaterConsumption}");

    // This is what is going to be used as a comparable in the GroupComparer below
    group.Id = a.ID;

    // This will create the iComparer that is needed to create the custom sorting of the groups
    parms.GroupComparer = Comparer<BrightIdeasSoftware.OLVGroup>.Create((x, y) => (x.GroupId.CompareTo(y.GroupId)));
};

The OLVColumn.GroupFormatter is lightly explained here: http://objectlistview.sourceforge.net/cs/recipes.html#how-do-i-put-an-image-next-to-a-group-heading

Upvotes: 2

Thomas N
Thomas N

Reputation: 633

You can force the grouping column as follows:

olv.ShowGroups = true;
olv.AlwaysGroupByColumn = olvColumn1;

If you want to show one value in the column and group by a different one you can use GroupByKeyGetter

olvColumn1.GroupKeyGetter = GroupKeyGetter;

Delegate would be something like:

private object GroupKeyGetter(object rowObject)
{
    var o = rowObject as MyClass;

    if(o == null)
        return "unknown";

    return o.ID;
}

Some stuff doesn't take affect till you call

olv.RebuildColumns();

Always Sort By (Arbitrary Function)

If you want to force sorting on some custom logic you can use ListViewItemSorter in the BeforeSorting event. This is similar to registering a CustomSorter (but that doesn't seem to work when ShowGroups is true).

olv.BeforeSorting += olv_BeforeSorting;

Then

private void olv_BeforeSorting(object sender, BrightIdeasSoftware.BeforeSortingEventArgs e)
{
    //example sort based on the last letter of the object name
    var s = new OLVColumn();
    s.AspectGetter = (o) => ((MyClass)o).Name.Reverse().First(); 

    this.olv.ListViewItemSorter = new ColumnComparer(
                s, SortOrder.Descending, e.ColumnToSort, e.SortOrder);
    e.Handled = true;
}

Upvotes: 4

Related Questions