WPF ItemsControl datacontext sorting - wpf

Ok, I have an ItemsControl binded to a List<IComparableObject>, each second the List objects change, so I have to resort them, so each second I call the List.Sort() method. Checking in the Watch panel in VS2008, I can tell the List gets sorted, but the ItemsControl doesn't. How can I make this work?
Thanks!

You have to sort the CollectionView:
List<MyObject> myInternalList = new List<MyObject>();
...
ICollectionView colView = CollectionViewSource.GetDefaultView(myInternalList);
colView.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
You have to get the default view from the List.
In this case, you don't have to sort the List, because the view will always be sorted. You can add as many SortDescriptions you want.
HTH

Related

ListView CollectionView sort lowest level

I've a question about how to sort items in a ListView, I thought this would be really easy, but I can't seem to work it out.
The ListView is bound to an observable collection view model... the items in the list view are grouped based on certain properties by setting up a CollectionViewSource and setting up GroupDescriptions:
BrowserItemCollectionView = CollectionViewSource.GetDefaultView(_browser);
//Set up filter
BrowserItemCollectionView.Filter = FilterBrowserItems;
//Set up grouping
PropertyGroupDescription L1PGD = new PropertyGroupDescription(nameof(BrowserItem.L1group));
PropertyGroupDescription L2PGD = new PropertyGroupDescription(nameof(BrowserItem.L2group));
PropertyGroupDescription L3PGD = new PropertyGroupDescription(nameof(BrowserItem.L3group));
BrowserItemCollectionView.GroupDescriptions.Add(L1PGD);
BrowserItemCollectionView.GroupDescriptions.Add(L2PGD);
BrowserItemCollectionView.GroupDescriptions.Add(L3PGD);
I then sort the groups with:
//Setup Sorting
BrowserItemCollectionView.SortDescriptions.Add(new SortDescription(nameof(BrowserItem.L1group), ListSortDirection.Descending));
BrowserItemCollectionView.SortDescriptions.Add(new SortDescription(nameof(BrowserItem.L2group), ListSortDirection.Descending));
BrowserItemCollectionView.SortDescriptions.Add(new SortDescription(nameof(BrowserItem.L3group), ListSortDirection.Descending));
This works well and sorts the groupings in Descending order.
What I now what to do is sort the actual items - the objects that are the lowest levels of the tree views.
What method do I use to sort the actual list view items?
Thanks.
What method do I use to sort the actual list view items?
You just add another SortDescription for a property of the "lowest level" item to BrowserItemCollectionView.SortDescriptions:
BrowserItemCollectionView.SortDescriptions.Add(
new SortDescription("PropertyOfItem", ListSortDirection.Descending));

ListView selection change doesn't remove an old item

I have a strange behavior with my WPF ListView Control.
ListViews ItemSource is Observable collection.the ItemSource is updated periodically.
When I'm selecting one of the item and then selecting other item and no item updated, everything is OK.
But when I'm selecting an item witch is updated while I'm standing on, then selecting other item, now I have two items selected instead of one.
When I'm looking with the debugger, I see the event args of SelectionChanged event. I see that added item is OK but no removed item.
Anyone knows what's the problem?
Thanks!
Edit:
My observable collection:
protected class CustomObservableCollection : ObservableCollection<T>
{
public void Refresh()
{
ListCollectionView lcv = (ListCollectionView)(CollectionViewSource.GetDefaultView(this));
lcv.Refresh();
}
}
The update method witch called when there is a change in some item:
public void RefreshItem(T domainObject)
{
foreach (T item in obsCollection) {
if (!DomainObjectComparer.Equals(domainObject, item)) continue;
DomainObjectCopier.CopyProperties(domainObject, item);
obsCollection.Refresh();
break;
}
}
It looks like your copier class makes two items in your collection equal (I think, inferring this from the limited amount of code above).
If two items or more are the same (equal) in a ListView, then selecting one will select all of them as an equality comparer is used in the selection logic.
Well, Apparently the problem was with the overridden GetHashCode() method of the ListView item object.
the hash code included all the fields in it's calculation. I remoed all the fields (properties) and now the overridden GetHashCode() is only calculating the hash based on item's ID. it solved the problem.
I also have Equals() method overridden.
If someone knows why it is related I will like to know.

How to sort items in ListView by column bound to an Observable Collection?

How to sort items in ListView by column bound to an Observable Collection ?
I've looked all over the place and I can't find anything easy enough or simple on this.
Is the example here too complicated? It just shows how to use a ListCollectionView to provide the data in the correct order, and to perform the sorting.
You can use SortDescriptions in CollectionViewSource. Here is an example. If you want it dynamically, you need to code around this. but this should give you an idea.
List<Product> products = Client.GetProductList();
public ICollectionView ProductView = CollectionViewSource.GetDefaultView(products);
ProductView.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));

How to keep a data-bound list reverse-sorted

I have a listbox bound to a collection. I would like the ListBox to always reverse the order of the items. This handler--hooked up to the control's load event--works for the initial load, but not thereafter. Ive tried using the SourceUpdated event but that doesnt seem to work.
How do I maintain a constant active sort?
MyList.Items.SortDescriptions.Add(New SortDescription("Content", ListSortDirection.Descending))
How is the collection stored that supplies the items for the ListBox? It should be a collection that supports INotifyCollectionChanged. The framework provides ObservableCollection<T> which you can use.
In the constructor of your ViewModel (or wherever the collection lives), you then get the DefaultView for adding the SortDescription. The CollectionView is like a layer on top of your collection, which you can use to sort, group, filter, etc. the items without actually affecting the underlying data source. The framework creates a default one for you. To get a reference to it, you can use code similar to the following:
var collectionView = CollectionViewSource.GetDefaultView(Widgets);
if(collectionView == null)
return;
collectionView.SortDescriptions.Add(new SortDescription("Content", ListSortDirection.Descending));
With that in place, you should be able to add items to the ObservableCollection<T> and the sort order will be maintained.
If your source collection is a List<T> or some other collection that doesn't implement INotifyCollectionChanged, there is no way WPF can detect when an item is added. You need to use a collection that implements INotifyCollectionChanged, like ObservableCollection<T>.
Also, the items in your collection need to implement INotifyCollectionChanged so that changes to the items are taken into account

ItemsControl - Bind Control's and Backing Collection's Sort Orders Together

Is there a way to bind an ItemsControl (like ListView or DataGrid) to a sorted collection such that:
whenever the collection is resorted via code, the ItemsControl automatically reflects the new sort order,
AND whenever the ItemsControl is sorted, it re-sorts the collection?
Thank you,
Ben
You'll need to use the
CollectionViewSource.GetDefaultView()
method to get the default view of your ObservableCollection and apply the sort on that.
For example, below I'm sorting the ObservableCollection named 'authors' by BookTitle.
ObservableCollection<Author> authors = new ObservableCollection<Author>();
authors = PopulateCollection();
// Sort by BookTitle
System.ComponentModel.ICollectionView colView;
colView = CollectionViewSource.GetDefaultView(authors);
colView.SortDescriptions.Add(new System.ComponentModel.SortDescription("BookTitle", ListSortDirection.Descending));
try to define this two attributes on the bining:
IsSynchronizedWithCurrentItem=true
BindsDirectlyToSource=true
i did not tried this but it might work..
Putting your items into an ObservableCollection and then binding to the ObservableCollection should do the trick. Any sorting done on the ObservableCollection should "translate" to the UI layer.

Resources