Metro App CollectionViewSource ObservableCollection Filter

吃可爱长大的小学妹 提交于 2020-01-01 06:41:47

问题


It appears that filtering an ObservableCollection with CollectionViewSource is not possible in WinRT:

See here!

I can filter using LINQ, but how do I get the UI to update if changes that affect the filtered data are made?


回答1:


I ended up writing my own class to achieve the desired effect:

public class ObservableCollectionView<T> : ObservableCollection<T>
{
    private ObservableCollection<T> _view;
    private Predicate<T> _filter;

    public ObservableCollectionView(IComparer<T> comparer)
        : base(comparer)
    {

    }

    public ObservableCollectionView(IComparer<T> comparer, IEnumerable<T> collection)
        : base(comparer, collection)
    {

    }

    public ObservableCollectionView(IComparer<T> comparer, IEnumerable<T> collection, Predicate<T> filter)
        : base(comparer, collection == null ? new T[] { } : collection)
    {
        if (filter != null)
        {
            _filter = filter;

            if (collection == null)
                _view = new ObservableCollection<T>(comparer);
            else
                _view = new ObservableCollection<T>(comparer, collection);
        }
    }

    public ObservableCollection<T> View
    {
        get
        { 
            return (_filter == null ? this : _view);
        }
    }

    public Predicate<T> Filter
    {
        get
        {
            return _filter;
        }
        set
        {
            if (value == null)
            {
                _filter = null;
                _view = new ObservableCollection<T>(Comparer);
            }
            else
            {
                _filter = value;
                Fill();
            }
        }
    }

    private void Fill()
    {
        _view = new ObservableCollection<T>(Comparer);
        foreach (T item in this)
        {
            if (Filter(item))
                View.Add(item);
        }
    }

    private int this[T item]
    {
        get
        {
            int foundIndex = -1;
            for (int index = 0; index < View.Count; index++)
            {
                if (View[index].Equals(item))
                {
                    foundIndex = index;
                    break;
                }
            }
            return foundIndex;
        }
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        base.OnCollectionChanged(e);

        if (_filter != null)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    foreach (T item in e.NewItems)
                        if (Filter(item))
                            View.Add(item);
                    break;

                case NotifyCollectionChangedAction.Move:

                    break;

                case NotifyCollectionChangedAction.Remove:
                    foreach (T item in e.OldItems)
                        if (Filter(item))
                            View.Remove(item);
                    break;

                case NotifyCollectionChangedAction.Replace:
                    for (int index = 0; index < e.OldItems.Count; index++)
                    {
                        T item = (T)e.OldItems[index];
                        if (Filter(item))
                        {
                            int foundIndex = this[item];
                            if (foundIndex != -1)
                                View[foundIndex] = (T)e.NewItems[index];
                        }
                    }
                    break;

                case NotifyCollectionChangedAction.Reset:
                    Fill();
                    break;
            }
        }
    }

    protected override void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        base.OnPropertyChanged(e);

        if (_filter != null)
        {
    // TODO: Implement code for property changes
        }
    }
}

Not yet perfect. So improvements/suggestions welcomed.

You can now bind this object, directly to a control using the View property.




回答2:


You need to make sure the filtering changes are observable, so you can set the source of the CollectionViewSource to an ObservableCollection and make the changes on that collection or assign a new Source of the CVS to a new, filtered collection.



来源:https://stackoverflow.com/questions/16244596/metro-app-collectionviewsource-observablecollection-filter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!