I have a list of "stuff" which needs to be filtered then displayed in a grouped and sorted manner. The data needed to calculate the grouping and sorting order is not available as simple properties - there needs to be some work done in code to calculate the order and groups.
CollectionViewSource lets me define custom filter and sort logic - so far so good. It also lets me bind GroupDescriptions to a value converter so that I can generate the group names.
The last thing I want to do is control the order that the generated groups appear and this is causing me pain!
Everything I see about CollectionViewSource.SortDescriptions says that it will sort groups by a property name, but I don't have a property available to sort by. SortDescriptions can't be bound to a value converter like GroupDescriptions can and I'm out of other ideas.
So - how do you implement custom sorting logic of CollectionViewSource groups?
This post on Bea Stollnitz' blog, and the GitHub repo, demonstrates how you can do that. You will have to sort by the criteria of your grouping first. Even if this is not a concrete property, it should be possible to sort your items using the same logic that you use to group them, isn't it?! Certainly, this is not possible using a SortDescription instance, but you could instead use the ListCollectionView.CustomSort property and specify an appropriate IComparer implementation.
Related
Let's say I have an indefinite amount of Branch objects and each one has a List with the employees of that branch.
I now want to list all employees of all branches grouped by their respective branch in one ListView element.
The only solution I come up with is to run through all branches, pull their employees and put them in a separate list which I then use as the ListView's ItemsSource. Is there an easier and/or more effective way?
If i understand correctly, you have a list of an object, and it has a other list in its properties. And you need sum of all inner lists.
See SelectMany
You can use it like
MyList.SelectMany(item=>item.OtherLists);
it gives you sum of all OtherList's elements.
For grouping, see GroupBy
and you can use it like that
Innerlist.GroupBy(item=>item.Id)
you should use GroupBy first, SelectMany later, based on your question, something like
Branches.GroupBy(branch=>branch.Name).SelectMany(item=>item.Employees)
and you can put them in a list(and bind them), or just set the ItemsSource.
So I've got an object that has an observable collection. Most places I bind to this collection I only want the user to select a single item. But in one place I want the combobox to include an all items option.
Is the way to do this simply with xaml converter?
It seems like doing it in the view model would be a good idea, but it's really a lot dependency object goop to basically wire up an collection that is two objects deep for an on change event, where as the xaml converter just works.
But I always feel like xaml converters should be generic and reusable, where in this instance, the xaml converter would be more of a one off.
Of course the third option would be to create one off list for UI in the object that contains the standard observable collection. But this seems to be mixing the logic and presentation in a way that makes me uncomfortable.
Take a look at CompositeCollection. It lets you concatenate multiple collections into a single collection -- sort of the XAML equivalent of the LINQ Concat. It implements INotifyCollectionChanged, so it should be able to react to changes if some of its inner collections are ObservableCollections.
CompositeCollection also lets you add individual elements, so you wouldn't even need to wrap your "All Items" in a collection of its own. (Instead, you have to wrap collections in a CollectionContainer. See the examples on the CompositeCollection doc page.)
I had a similar need, and ended up using the solution discussed in this article: How To Select Null/None in a ComboBox/ListBox/ListView.
You can replace the "(None)" string on line 98 with "All" or something similar. Then just add logic in your ViewModel to treat a null value as "All" in whatever manner is appropriate. It's a little annoying to have an extra class lying around but it makes the code a lot cleaner if you do need this in several places.
This article "Write a Sortable ObservableCollection for WPF" appears to be all that's needed (for me) to handle any need to sort ObservableCollection. However, there might be scenarios that need a more complex design. Or, on the other extreme, there may be a way to prevent this need for a sort by design. Am I on the right track here or is this question moot?
This depends on whether you are trying to persist the user-selected ordering, like if the user is prioritizing items.
If the sorting is for display purposes only as is more common, CollectionView and CollectionViewSource are well-adapted to sorting and filtering collections in various ways in the WPF UI.
I have created one application that allows you to Sort, filter, implace editing based on User interaction.
http://www.abhisheksur.com/2010/08/woring-with-icollectionviewsource-in.html
You can check this out, it might help. Sorted ObservableCollection is basically very expensive.
How can we get Number of rows Present in Listview?
Couldn't you just use ListView.Items.Count?
Well, you see. When you bind a list view to some sort of collection (preferably some sort of observable collection) with some sort of type.
You can add/remove.
But you also have the functionality to say
observablecollection.count.
Now if you are adding the items inside the XAML.
a quick and easy way to access it is.
x:Name="name of the list"
then in the code behind say
(name of the list).count.
That should give you access within the code behind, or if you don't want to do it in the code behind. You will need some sort of window dictionary.
and you can access the (name of the list) through your dictionary.
in a WPF project with Linq to SQL, if you use the O/R - designer to create a simple structure with 3 that are all tied with forgin key relataions like so:
Customer <-- Orders <-- Items, and say i want a simpe window with 3 syncronized comboboxes
when you select a customer you see only his orders and when you select an Order you see only the Items for that Order. all of this is simple....
Lets say i want to add filtering capablities to all the comboboxes. how would i do that if i want to use the entity objects from the LINQ dbml file?
Edit - Elaborating on filtering.
i would like to filter the in memory collection without the need to query the database again, the filter can be a textbox that is over the combobox, that doest matter, my problem is that i cant filter the comboboxes because the are bound to an EntitySet through the L2S and dont implement filtering.
Thanks,
Eric
I would look into using CollectionViewSource. Bea Stollnitz has a good primer on it here and I used this blog post to show me how to filter. This will let you filter and sort without having to use the database and is pretty fast.