当我在WPF中使用数据绑定时,我的目标控件正在侦听绑定源上的事件。例如,我ListView
可能会CollectionChanged
监听ObservableCollection
个事件。
如果事件源的生命周期预计超过事件监听器的生命周期,则可能存在内存泄漏,应使用weak event pattern。
WPF数据绑定是否遵循弱事件模式?如果我的ObservableCollection
的寿命超过ListView
,我的ListView
会被垃圾收集吗?
这就是我怀疑WPF控件没有实现弱事件模式的原因。如果他们这样做,我希望将 DerivedListView Collected!
和DerivedTextBlock Collected!
输出到控制台。相反,只有DerivedTextBlock Collected!
是。
修复代码中的错误后,会收集这两个对象。我不确定该怎么想。
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace LeakDetector
{
public class DerivedListView : ListView
{
~DerivedListView()
{
Console.WriteLine("DerivedListView Collected!");
}
}
public class DerivedTextBlock : TextBlock
{
~DerivedTextBlock()
{
Console.WriteLine("DerivedTextBlock Collected!");
}
}
public partial class Window1 : Window
{
// The ListView will bind to this collection and listen for its
// events. ObColl will hold a reference to the ListView.
public ObservableCollection<int> ObColl { get; private set; }
public Window1()
{
this.ObColl = new ObservableCollection<int>();
InitializeComponent();
// Trigger an event that DerivedListView should be listening for
this.ObColl.Add(1);
// Get rid of the DerivedListView
this.ParentBorder.Child = new DerivedTextBlock();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
this.ParentBorder.Child = null;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
Console.WriteLine("Done");
}
}
}
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LeakDetector"
x:Class="LeakDetector.Window1"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Height="300" Width="300"
Title="Leak Detector">
<Border x:Name="ParentBorder">
<local:DerivedListView ItemsSource="{Binding Path=ObColl}" />
</Border>
</Window>
答案 0 :(得分:10)
实质上,WPF控件本身与弱事件无关。相反,有一些与WPF的绑定引擎相关的类实现了弱事件模式。类PropertyChangedEventManager实现了WeakEventManager。如果你使用Reflector,你会看到几个类在MS.Internal.Data命名空间中实现IWeakEventListener(特别是一个直接使用PropertyChangedEventManager的MS.Internal.Data.PropertyPathWorker类)。 WPF在内部使用这些对象来执行数据绑定。
ItemsControls和CollectionChanged事件是一个不同的故事,与Bindings无关。看,您可以在后面的代码中执行类似“listView.ItemsSource = myObservableCollection”的操作,并且收集更改的通知仍然有效。这里没有涉及绑定对象。在这里,一组不同的“弱事件相关类”正在发挥作用。 ItemCollection和ItemContainerGenerator实现了IWeakEventListener,它们与CollectionChangedEventManager(实现WeakEventManager)一起工作。
答案 1 :(得分:2)
您链接的MSDN文章的第二句非常清楚地表明WPF确实使用了弱事件模式。实际上,它甚至可以说WPF 引入了模式。
修改强>
我希望找到一些明确说明“WPF控件实现弱事件模式”的文档。 - emddudley
在做了一些研究之后,我认为这个问题的答案是“不”,我认为理由答案是“不”是WPF不希望UI控件是暂时的。虽然有一个CollectionChangedEventManager
类专门针对CollectionChanged
事件的弱事件而构建,但是没有任何支持数据绑定的控件似乎实现IWeakEventListener
,这对于使用弱事件是必要的。采集。
我认为模式和用法是为ViewModel而不是View构建的,View比View更可能是暂时的。
编辑2:
修复代码中的错误后,会收集这两个对象。因此我相信WPF控件使用弱事件模式。
有趣的结果。如果他们确实实现了弱事件,他们必须在内部执行。