Контролируют ли WPF слабые события в своих привязках?

Когда я использую привязку данных в WPF, мои целевые элементы управления прослушивают события в источнике привязки. Например, у меня может быть ListView прослушивание CollectionChanged события на ObservableCollection.

Если время жизни источника события будет превышать время жизни прослушивателя событий, возникает потенциальная утечка памяти, а слабый шаблон события.

Поддерживается ли привязка данных 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>

Ответы

Ответ 1

В сущности, сами WPF сами не имеют ничего общего со слабыми событиями. Вместо этого существуют определенные классы, связанные с механизмом привязки WPF, которые реализуют шаблон слабых событий. Класс PropertyChangedEventManager реализует WeakEventManager. И если вы используете Reflector, вы увидите, что несколько классов реализуют IWeakEventListener в пространстве имен MS.Internal.Data(в частности, это класс MS.Internal.Data.PropertyPathWorker, который напрямую использует PropertyChangedEventManager). Эти объекты используются WPF для внутренней привязки данных.

ItemsControls и CollectionChanged - это разные истории и не имеют ничего общего с Bindings. Смотрите, вы могли бы сделать что-то вроде "listView.ItemsSource = myObservableCollection" в коде позади, и уведомление об изменении коллекции все равно будет работать. Здесь нет объектов привязки. Здесь используется другой набор "классов, связанных с слабым событием". ItemCollection и ItemContainerGenerator реализовать IWeakEventListener, и они работайте совместно с CollectionChangedEventManager (который реализует WeakEventManager).

Ответ 2

Во втором предложении статьи MSDN, в которую вы четко указали, указано, что WPF использует шаблон слабых событий. Фактически, это доходит до того, что WPF представил шаблон.

Edit:

Я надеялся найти документацию, в которой явно указано, что "элементы управления WPF реализуют шаблон слабых событий". - emddudley

После некоторого исследования я думаю, что ответ на этот вопрос "нет", и я думаю, что причина, по которой ответ "нет", заключается в том, что WPF не ожидает, что элементы интерфейса будут временными. Хотя существует класс CollectionChangedEventManager, созданный специально для слабых событий в отношении события CollectionChanged, ни один из элементов управления, поддерживающих привязку данных, не реализуется IWeakEventListener, что необходимо для использования слабых событий против коллекции.

Я думаю, что шаблон и использование построены для ViewModel, а не для представления, который, скорее всего, будет временным, чем представление.

Edit2:

После исправления ошибки в коде оба объекта собираются. Поэтому я считаю, что элементы управления WPF используют шаблон слабых событий.

Интересный результат. Если они реализуют Слабые события, они должны делать это внутренне.