Yohanes Nurcahyo
Yohanes Nurcahyo

Reputation: 621

Are There Any CollectionViewSource Alternative with Generic?

For my WPF application, I need CollectionViewSource to enable selection, filtering, sorting, and grouping in a collection. But CollectionViewSource is not a type safe collection like IList, the property View.CurrentItem is an object for example. We need to cast the items if we use them.

Are there any CollectionViewSource alternatives that support Generic? Or maybe anybody know the reason why CollectionViewSource is not a generic?

=============================

I made a generic CollectionViewSource based on standard CollectionViewSource. Any comment whether it is a better alternative for collection class that is instantiated outside XAML? Or there is another better alternative?

Edit 1: Add Generic CollectionViewSource

namespace Data
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Data;

    public class CollectionViewSource<T> : CollectionViewSource
    {
        public T CurrentItem => this.View != null ? (T)this.View.CurrentItem : default(T);

        public new IEnumerable<T> Source
        {
            get
            {
                return (IEnumerable<T>)base.Source;
            }

            set
            {
                base.Source = value;
            }
        }

        public IEnumerable<T> ViewItems => this.View != null ? Enumerable.Cast<T>(this.View) : (IEnumerable<T>)null;

        public CollectionViewSource(IEnumerable<T> source)
        {
            this.Source = source;
        }

        public bool Contains(T item)
        {
            return this.View != null && this.View.Contains(item);
        }

        public IEnumerable<T> Groups()
        {
            return this.View.Groups.Cast<T>();
        }

        public void MoveCurrentTo(T item)
        {
            this.View?.MoveCurrentTo(item);
        }
    }
}

Upvotes: 5

Views: 2724

Answers (2)

Shahin Dohan
Shahin Dohan

Reputation: 6922

You can actually just bind to your ObservableCollection (or any collection) and then call CollectionViewSource.GetDefaultView for that collection instance, then apply a filter, and your DataGrid (or other items controls) will get filtered. This way you can have your cake and eat it too :-)

The reason for this, I suspect, is because WPF list controls never actually bind to normal .NET collections, but always call CollectionViewSource.GetDefaultView behind the scenes, and that seems to return the same instance as the one you already created, if you created one.

Codebehind:

MySourceCollection = new[]
{
    new ViewModel(1, "first"),
    new ViewModel(2, "second"),
    new ViewModel(3, "third"),
    new ViewModel(4, "fourth")
};

MyListView = CollectionViewSource.GetDefaultView(MySourceCollection);
MyListView.Filter = o => ((ViewModel)o).Number >= 3;

XAML:

<DataGrid ItemsSource="{Binding MySourceCollection}" />

Result:

Research #QAnon

I don't know whether this is recommended, but I don't see any problem yet. Just remember that if you reinitialize your source list, you have to call CollectionViewSource.GetDefaultView again and reapply your filters.

Upvotes: 3

MikeT
MikeT

Reputation: 5500

The reason why its not generic is that the type safety should be in your underlying collection not your view.

The CollectionViewSource is purely for formatting the display of the data, so like a combo and list controls are not typed neither is CollectionViewSource and for exactly the same reason, because they need to work with anything that is given to them

as an example you have a Students Collection, you want to display this in a combo but your also want to be able to select "NEW STUDENT" new student isn't a student so can't be added to the student collection but is a perfectly valid combo item so while the underlying collection has to be Type safe, enforcing the same on the combo is limiting and not protective, out side of your view your code really shouldn't care if values are sorted or not that's usually just a human thing

as for your generic CollectionViewSource, it depends how your are using it if its a good idea not however the type safety should be superflous because your underlying collection should already be doing this.

I would suggest having an ObservableCollection<T> as the source of your CollectionViewSource and then just forgetting about Type safing the display

Upvotes: 1

Related Questions