我有一个绑定到 CollectionViewSource 的 WPF ListView。它的来源绑定到一个属性,如果用户选择一个选项,它可以改变。
当列表视图源由于属性更改事件而更新时,所有内容都会正确更新,但不会刷新视图以考虑 CollectionViewSource 过滤器中的任何更改。
如果我将处理程序附加到 Source 属性绑定到的 Changed 事件,我可以刷新视图,但这仍然是旧视图,因为绑定尚未更新列表。
当源更改时,是否有一种不错的方法可以使视图刷新并重新评估过滤器?
干杯
我有一个绑定到 CollectionViewSource 的 WPF ListView。它的来源绑定到一个属性,如果用户选择一个选项,它可以改变。
当列表视图源由于属性更改事件而更新时,所有内容都会正确更新,但不会刷新视图以考虑 CollectionViewSource 过滤器中的任何更改。
如果我将处理程序附加到 Source 属性绑定到的 Changed 事件,我可以刷新视图,但这仍然是旧视图,因为绑定尚未更新列表。
当源更改时,是否有一种不错的方法可以使视图刷新并重新评估过滤器?
干杯
框架不支持基于 PropertyChanged 事件更新 CollectionView.Filter。有很多解决方案。
1) 在你的集合内的对象上实现IEditableObject接口,并在改变过滤器所基于的属性时调用BeginEdit和EndEdit。您可以在 Dr.WPF 的优秀博客上阅读更多相关信息: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事件,但是不要忘记在对象被移除的时候解开事件处理函数,否则可能会导致内存泄漏
或者
将 TestCollection 注入 TestClass 并在 TestProp 设置器中使用 RefreshFilter 函数。无论如何,这里的魔法是由 NotifyCollectionChangedAction.Replace 完成的,它完全更新了项目。
您是在更改分配给 的实际集合实例CollectionViewSource.Source,还是只是PropertyChanged在它绑定的属性上触发?
如果设置了该Source属性,则应该为新源集合中的每个项目调用过滤器,所以我认为正在发生其他事情。您是否尝试过Source手动设置而不是使用绑定并查看您是否仍然得到您的行为?
编辑:
您使用的是CollectionViewSource.View.Filter属性还是CollectionViewSource.Filter事件?当CollectionView你设置一个新的时,它会被吹走Source,所以如果你有一个Filter设置,CollectionView它将不再存在。
我找到了一个特定的解决方案,用于将 ObservableCollection 类扩展为监视它包含的对象的属性变化的类。
这是我对代码进行了一些修改:
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);
}
}
}
聚会可能有点晚了,但以防万一
你也可以使用 我通过这篇博文找到的CollectionViewSource.LiveSortingProperties 。
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));
我找到了一个相对简单的方法来做到这一点。我将只读的 ICollectionView 属性更改为获取/设置并添加了引发的属性事件:
Property TypeFilteredCollection As ICollectionView
Get
Dim returnVal As ICollectionView = Me.TypeCollection.View
returnVal.SortDescriptions.Add(New SortDescription("KeyName", ListSortDirection.Ascending))
Return returnVal
End Get
Set(value As ICollectionView)
RaisePropertyChanged(NameOf(TypeFilteredCollection))
End Set
End Property
然后更新,我刚刚使用:
Me.TypeFilteredCollection = Me.TypeFilteredCollection
如果您没有地方触发该更新,这显然是行不通的。