【问题标题】:Metro App CollectionViewSource ObservableCollection FilterMetro App CollectionViewSource ObservableCollection 过滤器
【发布时间】:2013-04-26 20:20:25
【问题描述】:

在 WinRT 中似乎无法使用CollectionViewSource 过滤ObservableCollection:

See here!

我可以使用 LINQ 进行过滤,但是如果进行了影响过滤数据的更改,我如何让 UI 更新?

【问题讨论】:

    标签: windows-runtime microsoft-metro winrt-xaml observablecollection collectionviewsource


    【解决方案1】:

    我最终编写了自己的类来达到预期的效果:

    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
            }
        }
    }
    

    还不完美。因此欢迎提出改进/建议。

    您现在可以使用 View 属性将此对象直接绑定到控件。

    【讨论】:

    • 并不完美……还没有!你能展示一个简单的用法示例吗?了解这个类的目的/优势会更好。
    • 目的:一个可排序和过滤的 ObservableCollection。创建这个对象的一个​​实例,像通常使用 ObservableCollection 一样使用。具有 Predicate 形式的过滤器属性,因此您可以过滤数据。然后在绑定到控件时,绑定到 View 属性。就是这样!
    • 不错的解决方案。我暂时将在我的项目中使用它!
    • 我不明白采用 IComparer&lt;T&gt; 参数的构造函数重载的存在。 ObservableCollection&lt;T&gt; 中不存在这些重载,因此 a) 在此视图实现中似乎不需要它们,并且 b) 上面的代码不会编译,因为 base 调用无效(重载基类中不存在)。
    【解决方案2】:

    您需要确保过滤更改是可观察到的,因此您可以将 CollectionViewSource 的源设置为 ObservableCollection 并对该集合进行更改或将 CVS 的新 Source 分配给新的, 过滤的集合。

    【讨论】:

    • 我有一个源 ObservableCollection,我对其进行过滤并返回 IEnumerable。然后我将它传递给 ObservableCollection 的构造函数并分配给 CollectionViewSource。更新发生在源 ObservableCollection 上。现在它们是源集合和过滤集合之间的断开连接,因此过滤器不会拾取对源的更改。我该如何克服这个问题?
    • 您需要重新过滤和分配。或者在更新原始集合时更新过滤集合。
    • 我有...请参阅下面的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-14
    • 1970-01-01
    • 2011-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多