Привязка к словарю, сообщается об утечке памяти, как исправить?

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

Другие вопросы по тегам