Контролируют ли 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 используют шаблон слабых событий.
Интересный результат. Если они реализуют Слабые события, они должны делать это внутренне.