What is the proper usage of CollectionView(Source) in MVVM pattern?

273 views Asked by At

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:

  • ObservableCollection lies in System.ComponentModel, so we may treat it as non-platform (safe to use inside viewmodel).
  • CollectionViewSource resides in PresentationFramework assembly, so i treat this class as WPF-native, so platform and thus unusable in viewmodels.
  • CollectionView also resides in PresentationFramework, so I cannot use it in viewmodel either
  • ICollectionView (which obviously CollectionView implements) in turn resides in System.ComponentModel (WindowsBase), so it seems to be non-platform.

I always struggled, how to properly implement the whole CollectionViewSource-thing. Usually I:

  • Place CollectionViewSource in window/control resources and bind its Source to viewmodel's property
  • Bind list control's ItemsSource property to the CollectionViewSource by 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 CollectionViewSource in resources as earlier
  • Bind ItemsSource the same way as earlier, but then
  • Extract ICollectionView from CollectionViewSource in 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)?

3

There are 3 answers

0
M. Goppelt On

The problem is generally, is sorting, filtering and grouping considered part of presentation or business logic?

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.

0
Andy On

There are several reasons why I would not usually use collectionview or collectionviewsource for filtering and sorting.

Two outweigh most of them though:

Collectionview filtering and sorting is inefficient.

That might not matter, depends on your data.

If you have just a few hundred rows you're possibly going to deal with then it doesn't matter if it's slow.

There is often too much data.

If you have thousands of transactions a second you're obviously not going to pull that table across onto the client and then start thinking about filtering it. It's not going to even get there.

You don't need very many rows before it becomes advisable to do that filtering on the server. When you have substantial amounts of data ( and most systems I have worked on do ) you need to think about paging as well. That means you need to sort on the server as well.

I also do not like sorting on the UI so much.

It's expensive to test UI based logic. I prefer minimal code in the UI. This BTW is the reason to encapsulate any UI code you have for re-use in behaviours. This is why you don't want much code in your code behind.

I would not be too concerned about viewmodel libraries necessitating "view" dll. With two caveats: Unless

a) You're developing with MAUI or some such re-usability in mind

OR

b) Your automated test vm is linux.

Otherwise it's academic what windows only dll are required. The wpf app will definitely require those when delivered.

0
Eder Cardoso On

I think it's important to try to avoid using Presentation Framework classes inside your ViewModel cause MVVM frameworks come and goes away all the time. Imagine if you have your VM's isolated on a pure .NET 7 project and on top of it you have another WPF project that references the first project to use these ViewModels as the DataContext of it's views. Then a few years later another MVVM based UI framework like UWP appears on the market. All you have to to it's to create a UWP on that solution and re-use your VM's on the brand new UWP project. Then a few months later another cool MVVM based UI framework appears once again like WinUI 3. The same will apply.

Other scenario, let suppose you have a native desktop Windows app (It could be WPF, UWP or WinUI) and then you decide make it run on mobile using MAUI, Avalonia or UNO. If you have all of your ViewModels decoupled from any specific UI framework you can put these VM's on a pure .NET Standard / .NET 6,7,8 project, and then use these same VM's on all of your UI specific projects.

So IMO despite of being hard to make your VM's UI-Framework agnostic, it should make your code more reusable and that should pay the bill in the long run.