Or am I simply lost in my path to enlightenment? I shall not dissert anymore, but hope to hear from the good Dr, perhaps in a blogpost touching this subject as I feel it to be of greater interest to the public health in the land of wpf. The true path will lead you to a new feature in. The binding engine will automatically generate a ListCollectionView for such a collection.
The ListCollectionView class provides support for sorting, grouping, and filtering your collection when it is the ItemsSource for an ItemsControl. Here is what the ListBox declaration might look like: You can download the sample for this post to see the complete item template, item container style, and group item style. Dynamically Updating Items is Problematic Ideally, applying a sort order to a CollectionView would result in a grouped and sorted view of the collection that is fully maintained even when items within the collection are changed.
Unfortunately, a ListCollectionView only groups and sorts its items when the view is first created or when new items are added to the source collection, assuming that the source collection is observable. Furthermore, if Bart finally gets the operation he deserves and secretly desires and his gender is updated accordingly, the changed item will not move to its proper group.
Here is some simple code to perform these changes: Items as Character; bart. Female; The image below depicts the sorting and grouping errors that are present after these changes: Note, that the item template did indeed update according to the name and gender change because the Character object raises the appropriate change notifications for these properties , but the ListCollectionView did not update its view of the items. As a result, the changed item is no longer in the correct sort location or group.
Refreshing a CollectionView If you are using. Then the items will once again be properly grouped and sorted.
Here is a routine that includes the Refresh call: Refresh ; After calling Refresh , the modified character now appears in the correct group and sort location, as shown here: Unfortunately, the Refresh method results in a complete regeneration of the view.
It is a rather drastic operation, to say the least. The ItemContainerGenerator for the ListBox receives this notification and responds by discarding all the existing visuals for the items. It then completely regenerates new item containers and visuals. Again, this is a drastic and often very expensive operation. For the mundane reasons, keep reading… otherwise, feel free to skip ahead to A Better Option.
Theoretically, you could derive your own custom collection view from the ListCollectionView class and override its Refresh method.
Then you could perhaps implement a routine that intelligently regenerates the view in a minimalistic manner by comparing the source collection to the view collection. Such a routine would need to move existing items to their new locations in the view, add items that were not previously present, and remove items that should no longer be present.
For each change, the view would need to raise a very specific CollectionChanged notification Add, Remove, or Move for consumption by the ItemContainerGenerator of the owning ItemsControl. Not only would such a synchronization routine be complex, but it is also likely to be even more expensive than simply resetting the entire collection. There will be some number, n, where discrete Add, Remove, and Move change notifications for n or fewer changes is indeed more performant than a single Reset notification.
Unfortunately, it will be very difficult to heuristically determine the appropriate value for n. Remove and Re-Add A better approach, especially if you are stuck on pre Namely, do not call Refresh at all, but instead, remove the target item from the observable collection, modify its properties, and then re-add it to the collection, as shown here: Remove bart ; bart.
Add bart ; The ListCollectionView will detect the removal of the old item and raise the appropriate Remove notification so that the ItemContainerGenerator can remove the associated container and visuals. It will also detect the addition of the modified item and insert it at the correct location within its view of the source collection again, per the grouping, sorting, and filter criteria.
Then it will raise the necessary Add notification so that a new item container and item visuals can be generated. This solution is obviously not perfect! For example, if the Bart character was the current item before it was removed from the collection, that state will be lost.
An Even Better Option: IEditableObject As mentioned earlier,. Namely, it allows you to implement an IEditableObject interface on your datamodel objects or on your viewmodel objects, if you are using the model-view-viewmodel pattern. This new interface allows for transactional changes edit, cancel, and commit on the object. This interface works in conjunction with collection items that implement the IEditableObject interface. In this new approach, when you need to change an item, you can first call the EditItem method of the collection view, then make the required changes to the item, and finally, call the CommitEdit method of the collection view.
As long as you know the source collection is an IList, you can safely call the IEditableCollectionView methods directly on the Items property and the ItemCollection class will delegate the call to the appropriate underlying collection view. Rather, these properties will be updated via bindings to properties on controls within the UI.
Such a template will often present a readonly view of the data using elements like TextBlock, Image, etc. The IEditableObject interface provides three transactional methods: I prefer to expose an additional readonly property on the editable object called IsInEditMode that can be used as a trigger for swapping between the view template and the edit template.
Below is my typical implementation of IEditableObject, as it would be implemented on the Character class in our example: When you run the sample, simply double-click an item or press F2 to enter edit mode. If you do not wish to commit your changes, press Escape. If you do wish to commit your changes, press Enter or simply select another character. When the changes are committed, you will notice that the item immediately moves to its proper location within the view.
The model-view-viewmodel pattern typically involves wrapping or replicating items and collections of known types within observable classes classes that provide change notifications like INotifyPropertyChanged and INotifyCollectionChanged and adding additional interfaces like IEditableObject to either the data model objects or the viewmodel objects to allow them to play nicely with the view.
That is always my preferred approach. Having said that, there are certainly times when you may not have the option of modifying the entity within your collection. The IEditableCollectionView interface is still your friend as long as you are targeting. It turns out that you can simply add the lines below to cause that specific item to be moved to the correct location within the view: There is no longer a need to explicitly refresh the entire view! Order now and receive these bonus gifts!
The downloadable sample included with this post covers the specific questions posed by Patient-X, but there is more to IEditableCollectionView. It also provides a convenient way to add and commit new items to the source collection. You can even use it to remove existing items from the source collection.
By leveraging members of the IEditableCollectionView interface for such changes, you can ensure that your view of the collection will remain accurate with respect to grouping, sorting, and filtering. For anyone who is hoping to get a published response to a WPF question, you should note as Patient-X has that the doctor is easily manipulated by wordsmithery.