views:

1174

answers:

3

The MSDN documentation states that an EntitySet implements IBindingList

(see 'Binding to EntitySets' at http://msdn.microsoft.com/en-us/library/bb546190.aspx)

However, it can be clearly seen that an EntitySet does not implement this interface!

So how do I sort?

For context, I'm binding this set to a WPF ListView.

For wider context of problem I'm trying to solve please see this post.

A: 

Could you do .ToList().OrderBy(x=>x.FieldToSortBy) ?

Vinny Brown
Of course, but that means creating another property.
Hainesy
A: 

Hainesy - judging by your comment on Vinny's post, I think you're missing his point... [I'm not presenting this as an answer to your question directly, I'm just elaborating on Vinny's point to clear up any possible confusion regarding that.]

Consider this object:

public class Person
{
    public string FirstName;
    public string MiddleInitial;
    public string LastName;

    public DateTime DateOfBirth { get; set; }

    public int Age
    {
        get
        {
            return (int)DateTime.Today.Subtract(DateOfBirth).TotalDays / 365;
        }
    }
}

now, assume I've got a list of Person set up called People

var people = new List<Person>();

And I've got a whole bunch of people in my list.

var sortedByLastName = people.OrderBy(o => o.LastName);
var sortedByFirstName = people.OrderBy(o => o.FirstName);
var sortedByAge = people.OrderBy(o => o.Age);
var sortedByAgeDesc = people.OrderByDescending(o => o.Age);
var sortedByLastThenFirst = people.OrderBy(o => o.LastName).ThenBy(o => o.FirstName);

That's for complex objects. If we've got a list of some primitive type, like a string:

var strings = new List<string>();

I want to sort them based on themselves - i.e. not by some property of my object

var sorted = strings.OrderBy(s => s);

This will sort on the object. You can also use the same idea if you're sorting complex objects that implement IComparable to sort by their default comparer.

An EntitySet can be sorted in a similar fashion, whether for a primitive type, or a complex object.

BenAlabaster
Hi, thanks... but the point of my question was how to find out how to sort an EntitySet directly. I am aware of how to sort a list. When I said "that means creating another property", I didn't quite mean the property to sort *on*.The issue is a little more complex if you read the post I linked to at the bottom of the question.
Hainesy
+7  A: 

EntitySet<T> doesn't implement IBindingList...it provides a method to get an IBindingList. You need to call .GetNewBindingList() to get an instance of EntitySetBindingList<T>, which derives from SortableBindingList<T>, which is a BindingList<T>. EntitySetBindingList is just a wrapper around the original EntitySet<T> it was created from, so any modifications to it are modifications to the original EntitySet.

EDIT: Sorting with BindingList:

To sort with a BindingList, you need to expose some kind of interface to allow sorting. Sorting is supported within the BindingList<T> class, but its through protected properties and methods. It should be possible to expose an expressive sort method with a wrapper:

public class EntitySetBindingWrapper<T>: BindingList<T>
{
    public EntitySetBindingWrapper(BindingList<T> root) : base(root)
    {
    }

    public void Sort(Expression<Func<T, P>> expr, ListSortDirection direction)
    {
        if (expr == null)
            base.RemoveSortCore();

        MemberExpression propExpr = expr as MemberExpression;
        if (propExpr == null) throw new ArgumentException("You must provide a property", "expr");

        PropertyDescriptorCollection descriptorCol = TypeDescriptor.GetProperties(typeof(T));
        IEnumerable<PropertyDescriptor> descriptors = descriptorCol.Cast<PropertyDescriptor>();
        PropertyDescriptor descriptor = descriptors.First(pd => pd.Name == propExpr.Member.Name);

        base.ApplySortCore(descriptor, direction);
    }
}

You should then be able to sort like so:

var bindingWrapper = new EntitySetBindingWrapper(myEntitySet.GetNewBindingList());
bindingWrapper.Sort(e => e.MyProperty, ListSortDirection.Ascending);

listView.DataSource = bindingWrapper;

There might be additional implementation for the EntitySetBindingWrapper class...such as fortwarding any normally public methods on BindingList<T> to the one provided to the constructor.

jrista
Thanks, I'm not sure this is going to take me down a dark alley though. If you read the post I linked to at the bottom of the question, there's probably something I'm missing in terms of databinding.
Hainesy
So, after reading that other post, he made the mistake of calling .ToList(). The binding source was probably updating its underlying list, but that list wasn't the EntitySet. Calling .ToList creates a NEW list object. BindingList supports sorting...somewhat of an archaic form...but it has to be exposed. You would need to create a BindingList wrapper that can wrap whats returned by GetNewBindingList(), and expose SortPropertyCore and SortDirectionCore. I'll post another answer with an example.
jrista
EntitySet<T> implements IListSource.GetList() by delegating to the GetNewBindingList() you mentioned (and caching the IBindingList result). If you bind an EntitySet<T> to a WinForms DataGridView through a BindingSource, you get column sorting support automatically. I don't know about WPF, but I would have thought it would work similarly.
Lucas
I guess it would depend on whether you want the user to be able to sort, or just want to present the user with a sorted list that can't be further sorted. If its the latter, then this will allow you to sort prior to binding.
jrista