更改Source时,CollectionViewSource Filter不会刷新

时间:2009-03-19 10:02:34

标签: wpf filter collections

我有一个绑定到CollectionViewSource的WPF ListView。它的源绑定到一个属性,如果用户选择了一个选项,它就会改变。

当列表视图源由于属性更改事件而更新时,所有内容都会正确更新,但视图不会刷新以考虑CollectionViewSource过滤器中的任何更改。

如果我将一个处理程序附加到Source属性绑定的Changed事件,我可以刷新视图,但这仍然是旧视图,因为绑定尚未更新列表。

是否有一种不错的方法可以在源更改时刷新视图并重新评估过滤器?

干杯

4 个答案:

答案 0 :(得分:12)

也许有点晚了,但这可能对其他用户有帮助,所以无论如何我都会发帖......

框架不支持基于PropertyChanged事件更新CollectionView.Filter。 围绕这个有很多解决方案。

1)在集合中的对象上实现IEditableObject接口,并在更改过滤器所基于的属性时调用BeginEdit和EndEdit。 您可以在Dr.WPF的优秀博客上阅读更多相关信息:Editable Collections by Dr.WPF

2)创建以下类并在更改的对象上使用RefreshFilter函数。

public class FilteredObservableCollection<T> : ObservableCollection<T>
{
    public void RefreshFilter(T changedobject)
    {
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, changedobject, changedobject));
    }        
}

示例:

public class TestClass : INotifyPropertyChanged
{
    private string _TestProp;
    public string TestProp
    {
        get{ return _TestProp; }
        set
        { 
            _TestProp = value;
            RaisePropertyChanged("TestProp");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}


FilteredObservableCollection<TestClass> TestCollection = new FilteredObservableCollection<TestClass>();

void TestClass_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    switch (e.PropertyName)
    {
        case "TestProp":
            TestCollection.RefreshFilter(sender as TestClass);
            break;
    }
}

在创建TestClass对象时订阅PropertyChanged事件,但不要忘记在删除对象时取消挂钩事件处理程序,否则可能导致内存泄漏

OR

将TestCollection注入TestClass并使用TestProp setter中的RefreshFilter函数。 无论如何,这里的魔力是由NotifyCollectionChangedAction.Replace完成的,它完全更新了项目。

答案 1 :(得分:2)

您是否正在更改分配给CollectionViewSource.Source的实际集合实例,或者您只是在其绑定的属性上触发PropertyChanged

如果设置了Source属性,则应该为新源集合中的每个项目调用过滤器,因此我认为还有其他事情正在发生。您是否尝试过手动设置Source而不是使用绑定并查看是否仍然可以获得您的行为?

修改

您使用的是CollectionViewSource.View.Filter属性还是CollectionViewSource.Filter事件?设置新的CollectionView时,Source会被吹走,所以如果Filter上设置了CollectionView,它将不再存在。

答案 2 :(得分:2)

我找到了一个特定的解决方案,用于将ObservableCollection类扩展为监视它包含的对象属性的更改here

以下是我的一些修改代码:

namespace Solution
{
public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
    {
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (e != null)  // There's been an addition or removal of items from the Collection
            {
                Unsubscribe(e.OldItems);
                Subscribe(e.NewItems);
                base.OnCollectionChanged(e);
            }
            else
            {
                // Just a property has changed, so reset the Collection.
                base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));

            }

        }

        protected override void ClearItems()
        {
            foreach (T element in this)
                element.PropertyChanged -= ContainedElementChanged;

            base.ClearItems();
        }

        private void Subscribe(IList iList)
        {
            if (iList != null)
            {
                foreach (T element in iList)
                    element.PropertyChanged += ContainedElementChanged;
            }
        }

        private void Unsubscribe(IList iList)
        {
            if (iList != null)
            {
                foreach (T element in iList)
                    element.PropertyChanged -= ContainedElementChanged;
            }
        }

        private void ContainedElementChanged(object sender, PropertyChangedEventArgs e)
        {
            OnPropertyChanged(e);
            // Tell the Collection that the property has changed
            this.OnCollectionChanged(null);

        }
    }
}

答案 3 :(得分:1)

聚会可能有点晚,但以防万一

您也可以使用 CollectionViewSource.LiveSortingProperties 我是通过 this 博文找到的。

public class Message : INotifyPropertyChanged
{
    public string Text { get; set; }
    public bool Read { get; set; }

    /* for simplicity left out implementation of INotifyPropertyChanged */
}
public ObservableCollection<Message> Messages {get; set}
ListCollectionView listColectionView = (ListCollectionView)CollectionViewSource.GetDefaultView(Messages);
listColectionView.IsLiveSorting = true;
listColectionView.LiveSortingProperties.Add(nameof(Message.Read));
listColectionView.SortDescriptions.Add(new SortDescription(nameof(Message.Read), ListSortDirection.Ascending));