4

I have an MVVM app and in a couple of my VMs I use CollectionViewSource.GetDefaultView(datasource) to initialize my ICollectionView and it works perfectly. My concern is that am I violating MVVM when using the CVS in my VMs?

Thank you all for your inputs

asdbabil
  • 91
  • 8
  • FYI, what I'm working on requires filtering and searching and the way I have the CVS in my VMs makes it easier and efficient for me unless there's an easier and more efficient way. – asdbabil Jun 10 '14 at 13:33
  • What specifically is wrong with "violating MVVM" from time to time? Is the code hard to write? Hard to read? Hard to test? Hard to change? Patterns are guidance, not law. – default.kramer Jun 10 '14 at 13:46
  • If I have a chance or a way to get something to look or work better, I would not hesitate to change it? – asdbabil Jun 10 '14 at 13:57
  • Why not just filter your collections in the view model using LinQ? – Sheridan Jun 10 '14 at 14:18

3 Answers3

5

I usually prefer exposing a collection in the view model and creating the collectionviewsource in XAML:

<Window.Resources>
    <CollectionViewSource x:Key="CollectionViewSource" Source="{Binding Items}">
        <i:Interaction.Behaviors>
            <behaviors:MyFilterLogic />
        </i:Interaction.Behaviors>
    </CollectionViewSource>
</Window.Resources>

<ItemsControl ItemsSource="{Binding Source={StaticResource CollectionViewSource}}" />

And the behavior class:

public class MyFilterLogic: Behavior<CollectionViewSource>
{
    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.Filter += AssociatedObjectOnFilter;
    }

    private void AssociatedObjectOnFilter(object sender, FilterEventArgs filterEventArgs)
    {
        // filter logic
    }
}

Some other experts actually don't mind exposing a CollectionView from within their view model: https://stackoverflow.com/a/979943/3351315

Community
  • 1
  • 1
eshaham
  • 869
  • 5
  • 12
  • You cannot use filters using this method. – Gusdor Jun 10 '14 at 13:29
  • Filtering and searching are required in my case – asdbabil Jun 10 '14 at 13:34
  • 2
    Sure you can - you can attach a custom Behavior logic to the CollectionViewSource object. I've modified my answer to show filtering. – eshaham Jun 10 '14 at 13:35
  • I left my implementation in the VMs. When I have time, I will go back and change things around using your approach. I'd give you a point but my SOF reputation isn't high enough. Thanks @eshaham – asdbabil Jun 11 '14 at 14:53
  • 1
    That's ok, I'm glad I could help – eshaham Jun 11 '14 at 15:11
  • Erno de Weerd, after reading all the inputs (including yours) and doing some more research, I concluded I can get away with leaving the implementation in my VMs for now, however I do want to go back and put the CVS in XAMl and I will use @eshaham's example. That's the reason I marked it as my answer. – asdbabil Jun 11 '14 at 18:08
1

Have a look at the answer to this question: Trigger Filter on CollectionViewSource

It shows an MVVM way of adding a CollectionSourceView by wrapping the traditional Items in the ViewModel.

As far as I can see this way you are not violating MVVM and still get to use the nice grouping, filtering and sorting features.

Do not feel bad because you are not using CollectionViewSources in Xaml as most examples do; in fact, I felt way better using them in code, in the ViewModel.

To manipulate the filtering, grouping and sorting I add commands to the ViewModel and in the execute I change the ICollectionView

Community
  • 1
  • 1
Emond
  • 50,210
  • 11
  • 84
  • 115
  • That's kindda what I have in my VMs – asdbabil Jun 10 '14 at 14:00
  • So how does that worry you. It doesn't violate MVVM as far as I can see – Emond Jun 10 '14 at 14:07
  • It's the fact that the CVS lives in the System.Windows.Data namespace – asdbabil Jun 10 '14 at 14:13
  • @asdbabil View models are written expressly for the application. You are unlikely to use the same view model with wpf, silverlight and/or windows phone 7. The idea of MVVM is to help you enforce separation of concerns. It is not a pattern to help you design reusable components. Try not to feel bad about coupling your view model assemblies to WPF, instead, worry about de-coupling your view model classes from the views that present them. – Gusdor Jun 10 '14 at 14:24
  • The fact that CVS is in the Data namespace is completely irrelevant. MVVM is at a different abstraction layer on top of that. – Emond Jun 10 '14 at 14:50
0

Things that might make you feel bad about it:

  • That factory method, GetDefaultView. It makes me feel dirty as well due to the static nature of the thing.
  • It is bound to the UI thread as you may know from changing ObservableCollection<T> from worker threads.

CollectionViewSource is an abstraction that allows you to specify how you would like to organise a collection but it does not display the collection - an ItemsControl does that. This is good MVVM!

Generally, I prefer to keep CollectionViewSource out of my view models unless i need filters simply because it makes my view model more complicated. A DataTemplateSelector or VisualStateGroup is often a simpler way to change collection presentation in the long run.

Gusdor
  • 14,001
  • 2
  • 52
  • 64
  • 1
    I'm not so much concerned with reusing my VMs in a SL or Windows phone 7 app. It's more like if we decided to move files around, lets say we decided to relocate all VMs in a class library assembly as opposed to being in a wpf application assembly. When using a CVS in a VM, it feels like instantiating a control such as a Combobox or Button in a VM. However after doing some research and getting some feedbacks here, I don't feel as bad :) – asdbabil Jun 11 '14 at 15:14