Привязка к словарю, сообщается об утечке памяти, как исправить?
dotMemory
говорит мне (скриншот ниже, "утечка привязки WPF"), что происходит утечка памяти при привязке к словарю, например так:
<ComboBox ItemsSource="{Binding Items, Mode=OneTime}"
DisplayMemberPath="Value"
SelectedValue="{Binding SelectedItem}"
SelectedValuePath="Key" />
Вопрос 1, всем: почему это утечка памяти (а именно, какой сценарий я должен использовать, чтобы столкнуться с проблемами) и как это исправить?
Queston 2, для экспертов dotMemory: почему в таком базовом приложении mvvm (см. Ниже) так много проблем? Должен ли я исправить эти проблемы? Как?
MCVE (создайте новое решение WPF, используйте приведенный выше код в xaml) код позади:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string property = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
public Dictionary<string, string> Items { get; } = new Dictionary<string, string>
{
{ "1", "One" },
{ "1a", "One and a" },
{ "2a", "Two and a" },
};
string _selectedItem = "1a";
public string SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
OnPropertyChanged();
}
}
}
1 ответ
Связывание целевых объектов, которые не реализуют интерфейс INotifyPropertyChanged или не используют режим привязки OneTime
Ответ 1: Xaml связан со словарем, который является коллекцией KeyValuePair, и его свойство Value указывается в качестве источника для DisplayMemberPath
, Предоставляемая KeyValuePair не реализует интерфейс INotifyPropertyChanged, и нет способа указать OneTime
режим привязки для DisplayMemberPath
, Таким образом, все элементы словаря останутся в памяти навсегда.
Ответ 2: dotMemory сообщает о потенциальных проблемах, только вы можете определить, является ли это реальной проблемой или нет. К сожалению,.NET сама создает дубликаты строк и создает массив, который никогда не будет заполнен данными, dotMemory также сообщает о них, потому что не может различить, созданы ли эти объекты "пользователем" или системой. Я бы порекомендовал вам посмотреть, почему у вас есть завершенные объекты, кажется, что вы забыли вызвать метод IDisposable.Dispose для некоторых объектов. И проверьте, созданы ли эти незаполненные массивы вами или нет.
Причина утечки заключается в том, что вы привязываетесь к объекту, который не реализует измененный INotifyProperty.
Когда мы привязываемся к свойству Value словаря, цель привязки начинает прослушивать уведомления об изменении свойства. Если свойство не является DependencyProperty или объектом, реализующим INotifyPropertyChanged, WPF прибегнет к подписке на событие ValueChanged класса System.ComponentModel.PropertyDescriptor, чтобы получать уведомления при изменении значения свойства исходного объекта.
Почему это проблема? Что ж, поскольку среда выполнения создает ссылку на этот дескриптор PropertyDescriptor, который, в свою очередь, ссылается на наш исходный объект, и среда выполнения никогда не узнает, когда освободить эту начальную ссылку (если явно не указано иное), как PropertyDescriptor, так и наш исходный объект останутся в объем памяти.
Это решается привязкой к ObservableDictionary