绑定到字典,报告内存泄漏,如何修复?

时间:2018-01-25 09:00:32

标签: c# wpf mvvm memory-leaks dotmemory

dotMemory告诉我(下面的截图," WPF绑定泄漏")绑定到字典时会出现内存泄漏,如下所示:

<ComboBox ItemsSource="{Binding Items, Mode=OneTime}"
          DisplayMemberPath="Value"
          SelectedValue="{Binding SelectedItem}"
          SelectedValuePath="Key" />

问题1 ,对每个人:为什么是内存泄漏(我应该使用什么场景来解决问题)以及如何修复它?

对于dotMemory专家来说,

Queston 2 :为什么如此基本的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();
        }
    }
}

2 个答案:

答案 0 :(得分:1)

  

绑定未实现的目标对象   INotifyPropertyChanged接口或不使用OneTime绑定   模式

回答1: Xaml绑定到Dictionary,它是KeyValuePair的集合,它的Value属性被指定为DisplayMemberPath的源。 暴露的KeyValuePair没有实现INotifyPropertyChanged接口,也无法为OneTime指定DisplayMemberPath绑定模式。因此,Dictionary的所有项目将永远留在记忆中。

回答2: dotMemory报告潜在的问题,只有你可以确定它是否是一个真正的问题。 不幸的是,.NET本身会生成字符串重复并创建一个永远不会被数据填充的数组,dotMemory也会报告它们,因为无法区分这些对象是否由&#34; user&#34;或者通过系统。 我建议你看看为什么你有最终的对象,似乎你忘记为某些对象调用IDisposable.Dispose方法。并检查这些未填充的数组是否由您创建。

答案 1 :(得分:0)

泄漏的原因是您绑定到未实现INotifyProperty更改的对象。

当我们绑定到字典的Value属性时,绑定目标将开始侦听属性更改通知。如果该属性不是 DependencyProperty 或实现 INotifyPropertyChanged 的对象,则WPF将诉诸于 System的 ValueChanged 事件。 .ComponentModel.PropertyDescriptor 类,用于在源对象的属性值更改时获取通知。

为什么这是个问题?好吧,由于运行时创建了对该PropertyDescriptor的引用,而该引用又引用了我们的源对象,并且运行时将永远不知道何时释放该初始引用(除非明确告知),因此PropertyDescriptor和我们的源对象都将保留在记忆。

通过绑定到 ObservableDictionary

解决