您的 CollectionViewSource 甚至没有持有对 _oNodeFolder 对象的引用 - 它持有对其属性的引用:lImgs 集合。因此,即使您将 _oNodeFolder 设置为 null,CollectionViewSource 仍然持有对原始 lImgs 集合的引用,而该集合又可能持有对其父集合的引用,而 GUI 也持有通过其View 对CollectionViewSource 本身的引用-因此引用链保持完整,并且仍然显示“旧”项,而且您可能存在严重的内存泄漏。
您不能只将绑定到CollectionViewSource 的Source 的父对象设置为null - 这不是它应该如何工作的。你要么:
- 根据需要在代码隐藏中设置和重置
CollectionViewSource.Source(并可能刷新绑定;有时在将其设置为新值之前将其设置为null 会有所帮助 - 我个人不喜欢这种方法)李>
- 永远不要将底层源集合设置为 null,只填充和清理它 - 这是使用
CollectionViewSource 的“默认”方式。
为了更好地控制我的集合及其显示方式(也来自代码隐藏),以及避免上述类型的“意外”内存泄漏(因为引用链的一部分未处理的,整个对象链仍然可能永远挂在内存中)如果我只需要一个 View 在集合上,我通常会使用一种解决方法:
public class ViewableCollection<T> : ObservableCollection<T>
{
private ListCollectionView _View;
public ViewableCollection(IEnumerable<T> items)
: base(items) { }
public ViewableCollection()
: base() { }
[XmlIgnore]
public ListCollectionView View
{
get
{
if (_View == null)
{
_View = new ListCollectionView(this);
_View.CurrentChanged += new EventHandler(InnerView_CurrentChanged);
}
return _View;
}
}
[XmlIgnore]
public T CurrentItem
{
get
{
return (T)this.View.CurrentItem;
}
set
{
this.View.MoveCurrentTo(value);
}
}
private void InnerView_CurrentChanged(object sender, EventArgs e)
{
this.OnPropertyChanged(new PropertyChangedEventArgs("CurrentItem"));
}
public void AddRange(IEnumerable<T> range)
{
if (range == null)
throw new ArgumentNullException("range");
foreach (T item in range)
{
this.Items.Add(item);
}
this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public void ReplaceItems(IEnumerable<T> range)
{
if (range == null)
throw new ArgumentNullException("range");
this.Items.Clear();
foreach (T item in range)
{
this.Items.Add(item);
}
this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public void RemoveItems(IEnumerable<T> range)
{
if (range == null)
throw new ArgumentNullException("range");
foreach (T item in range)
{
this.Items.Remove(item);
}
this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public void ClearAll()
{
IList old = this.Items.ToList();
base.Items.Clear();
this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public void CallCollectionChaged()
{
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
// necessary for xml easy serialization using [XmlArray] attribute
public static implicit operator List<T>(ViewableCollection<T> o)
{
return o == null ? default: o.ToList();
}
// necessary for xml easy serialization using [XmlArray] attribute
public static implicit operator ViewableCollection<T>(List<T> o)
{
return o == default || o == null ? new ViewableCollection<T>() : new ViewableCollection<T>(o);
}
}
然后,假设我有一个这样的类(为了清楚起见,我在此处跳过 PropertyChanged 实现):
public class VM_Persons
{
public ViewableCollection<Person> Persons { get; set; }
public string NameFilter { get; set; }
public VM_Perosns()
{
this.Persons.View.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
PropertyGroupDescription groupDescription = new PropertyGroupDescription("Country");
this.Persons.View.GroupDescriptions.Add(groupDescription);
this.Persons.View.Filter = method_Filter;
}
private bool method_Filter(object item)
{
if (item == null) return false;
if (item is Person p)
{
if (p.Name.Contains(NameFilter)) return true;
}
}
public void LoadData(List<Person> list)
{
this.Persons.ReplaceItems(list);
}
//....
}
在 GUI 中,我将像这样绑定到它(在此处绑定到 View 属性很重要):
<ListView ItemsSource="{Binding Path=Persons.View, Mode=OneWay}"/>
这样,我每个集合都有一个视图,并且没有任何内容包含我无法控制的泄漏引用。