WPF控件是否在绑定中使用弱事件?

时间:2010-09-14 19:44:20

标签: wpf data-binding weak-events

当我在WPF中使用数据绑定时,我的目标控件正在侦听绑定源上的事件。例如,我ListView可能会CollectionChanged监听ObservableCollection个事件。

如果事件源的生命周期预计超过事件监听器的生命周期,则可能存在内存泄漏,应使用weak event pattern

WPF数据绑定是否遵循弱事件模式?如果我的ObservableCollection的寿命超过ListView,我的ListView会被垃圾收集吗?


这就是我怀疑WPF控件没有实现弱事件模式的原因。如果他们这样做,我希望将DerivedListView Collected!DerivedTextBlock Collected!输出到控制台。相反,只有DerivedTextBlock Collected!是。

修复代码中的错误后,会收集这两个对象。我不确定该怎么想。

Window1.xaml.cs

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");
        }
    }
}

Window1.xaml

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

2 个答案:

答案 0 :(得分:10)

实质上,WPF控件本身与弱事件无关。相反,有一些与WPF的绑定引擎相关的类实现了弱事件模式。类PropertyChangedEventManager实现了WeakEventManager。如果你使用Reflector,你会看到几个类在MS.Internal.Data命名空间中实现IWeakEventListener(特别是一个直接使用PropertyChangedEventManager的MS.Internal.Data.PropertyPathWorker类)。 WPF在内部使用这些对象来执行数据绑定。

ItemsControls和CollectionChanged事件是一个不同的故事,与Bindings无关。看,您可以在后面的代码中执行类似“listView.ItemsSource = myObservableCollection”的操作,并且收集更改的通知仍然有效。这里没有涉及绑定对象。在这里,一组不同的“弱事件相关类”正在发挥作用。 ItemCollectionItemContainerGenerator实现了IWeakEventListener,它们与CollectionChangedEventManager(实现WeakEventManager)一起工作。

答案 1 :(得分:2)

您链接的MSDN文章的第二句非常清楚地表明WPF确实使用了弱事件模式。实际上,它甚至可以说WPF 引入了模式。

修改

  

我希望找到一些明确说明“WPF控件实现弱事件模式”的文档。 - emddudley

在做了一些研究之后,我认为这个问题的答案是“不”,我认为理由答案是“不”是WPF不希望UI控件是暂时的。虽然有一个CollectionChangedEventManager类专门针对CollectionChanged事件的弱事件而构建,但是没有任何支持数据绑定的控件似乎实现IWeakEventListener,这对于使用弱事件是必要的。采集。

我认为模式和用法是为ViewModel而不是View构建的,View比View更可能是暂时的。

编辑2:

  

修复代码中的错误后,会收集这两个对象。因此我相信WPF控件使用弱事件模式。

有趣的结果。如果他们确实实现了弱事件,他们必须在内部执行。