I'm trying to be as strict as possible when designing MVVM applications in terms of separating layers. In particular, I do my best to never leak anything platform-related to my viewmodels, and by platform I mean OS-related stuff, but also WPF-related stuff. Even though I barely ever reuse my viewmodels for different platforms, I try to keep them reusable as a good practice.
Some time ago I stumbled upon problem of sorting, grouping and filtering collections. The obvious solution for that in WPF is CollectionViewSource. But then things start to get complicated.
First, the facts:
ObservableCollectionlies inSystem.ComponentModel, so we may treat it as non-platform (safe to use inside viewmodel).CollectionViewSourceresides inPresentationFrameworkassembly, so i treat this class as WPF-native, so platform and thus unusable in viewmodels.CollectionViewalso resides inPresentationFramework, so I cannot use it in viewmodel eitherICollectionView(which obviouslyCollectionViewimplements) in turn resides inSystem.ComponentModel(WindowsBase), so it seems to be non-platform.
I always struggled, how to properly implement the whole CollectionViewSource-thing. Usually I:
- Place
CollectionViewSourcein window/control resources and bind itsSourceto viewmodel's property - Bind list control's
ItemsSourceproperty to theCollectionViewSourceby the kind-of weird binding:ItemsSource="{Binding Source={StaticResource cvsSource}}" - Implement filtering and sorting in the window/control, only consulting viewmodel when needed (e.g. getting filter string from it)
This seems kind of sketchy to me though.
The problem is generally, is sorting, filtering and grouping considered part of presentation or business logic?
Theoretically, presentation. But then one may quickly realize, that even though filtering a collection is related to presentation, knowing how to filter it boils down to business logic (-> viewmodel).
Since though ICollectionView seems to be platform-free, I consider the following scenario:
- Place
CollectionViewSourcein resources as earlier - Bind
ItemsSourcethe same way as earlier, but then - Extract
ICollectionViewfromCollectionViewSourcein the view (window/control) and pass it into the viewmodel. This will give viewmodel full control over sorting, filtering, selecting etc.
Is it a proper way of using CollectionViewSource? Or am I still getting things wrong and it should be solved yet in another way? Is there any documentation which shows, how to properly use CollectionViewSource according to MVVM requirements? (in terms: not instantiating it inside viewmodel)?
The purpose of layering is better maintainability through minimal interfaces. So, imho, "just give me the data, I'll present it" is the minimal interface. But reality is harsh, and so you might need to e.g. to filter your data in backend due to performance reasons. But this makes your interface more complex, so it's a compromise. I would almost always put grouping and sorting into the presentation category, because you can easily imagine very different views tailored to different user roles with different requirements about sorting and grouping.