ItemsControl 在 DataContext 设置为 null 后保留对先前 DataContext 的引用
ItemsControl keeps reference to previous DataContext after DataContext set to null
更新:澄清一下,这是一个关于内存泄漏的问题,而不是关于 UI 无法刷新以反映新的 null DataContext(那部分工作正常)。
看来,如果您将 ItemsControl
的 DataContext
设置为 null,它将继续保留对其旧数据上下文的引用,直到您为其分配一个新数据上下文不为空。您可以使用问题底部的代码确认这一点。单击 "Set DataContext to null",然后根据需要多次单击 "Collect garbage"。 "Foo finalized" 消息永远不会出现。然后点击"Set DataContext to empty object",再次收集垃圾,马上就能看到终结器运行。
我的应用程序发生内存泄漏,原因是我的一个 ItemsControls
(一个 DataGrid
)会在 TheGrid.DataContext = null
之后释放对旧数据上下文的所有引用.为什么不呢?这是预期的行为吗?
更新:点击"Set DataContext to null"后VS2015诊断工具提供的root路径如下所示。在 Foo
本身来自我的代码之后,我不认为任何事情:
Foo
ListDictionary+DictionaryNode
ListDictionary
ListDictionary+DictionaryNode
ListDictionary
HybridDictionary
Object[]
[强手柄]
XAML:
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<ItemsControl ItemsSource="{Binding Foos}" />
<Button Content="Set DataContext to null" Click="SetDataContextToNullClicked"/>
<Button Content="Set DataContext to empty object" Click="SetDataContextToEmptyObjectClicked" />
<Button Content="Collect garbage" Click="CollectGarbageClicked"/>
</StackPanel>
</Window>
C#:
namespace WpfApplication
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows;
public class Foo
{
~Foo()
{
Debug.Print("Foo finalized");
}
}
public class FoosViewModel // implementing INotifyPropertyChanged here doesn't help
{
public FoosViewModel(IEnumerable<Foo> foos)
{
Foos = foos;
}
public IEnumerable<Foo> Foos { get; }
}
public partial class MainWindow
{
public MainWindow()
{
DataContext = new FoosViewModel(Enumerable.Repeat(new Foo(), 1));
InitializeComponent();
}
private void SetDataContextToNullClicked(object sender, RoutedEventArgs e)
{
DataContext = null;
}
private void SetDataContextToEmptyObjectClicked(object sender, RoutedEventArgs e)
{
DataContext = new FoosViewModel(Enumerable.Empty<Foo>());
}
private void CollectGarbageClicked(object sender, RoutedEventArgs e)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
你可以在这里得到解释
使用列表会导致强引用(内存泄漏)。简单的解决方案就是将 List
更改为 ObservableCollection
,除非视图(本身)被释放
更新:澄清一下,这是一个关于内存泄漏的问题,而不是关于 UI 无法刷新以反映新的 null DataContext(那部分工作正常)。
看来,如果您将 ItemsControl
的 DataContext
设置为 null,它将继续保留对其旧数据上下文的引用,直到您为其分配一个新数据上下文不为空。您可以使用问题底部的代码确认这一点。单击 "Set DataContext to null",然后根据需要多次单击 "Collect garbage"。 "Foo finalized" 消息永远不会出现。然后点击"Set DataContext to empty object",再次收集垃圾,马上就能看到终结器运行。
我的应用程序发生内存泄漏,原因是我的一个 ItemsControls
(一个 DataGrid
)会在 TheGrid.DataContext = null
之后释放对旧数据上下文的所有引用.为什么不呢?这是预期的行为吗?
更新:点击"Set DataContext to null"后VS2015诊断工具提供的root路径如下所示。在 Foo
本身来自我的代码之后,我不认为任何事情:
Foo
ListDictionary+DictionaryNode
ListDictionary
ListDictionary+DictionaryNode
ListDictionary
HybridDictionary
Object[]
[强手柄]
XAML:
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<ItemsControl ItemsSource="{Binding Foos}" />
<Button Content="Set DataContext to null" Click="SetDataContextToNullClicked"/>
<Button Content="Set DataContext to empty object" Click="SetDataContextToEmptyObjectClicked" />
<Button Content="Collect garbage" Click="CollectGarbageClicked"/>
</StackPanel>
</Window>
C#:
namespace WpfApplication
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows;
public class Foo
{
~Foo()
{
Debug.Print("Foo finalized");
}
}
public class FoosViewModel // implementing INotifyPropertyChanged here doesn't help
{
public FoosViewModel(IEnumerable<Foo> foos)
{
Foos = foos;
}
public IEnumerable<Foo> Foos { get; }
}
public partial class MainWindow
{
public MainWindow()
{
DataContext = new FoosViewModel(Enumerable.Repeat(new Foo(), 1));
InitializeComponent();
}
private void SetDataContextToNullClicked(object sender, RoutedEventArgs e)
{
DataContext = null;
}
private void SetDataContextToEmptyObjectClicked(object sender, RoutedEventArgs e)
{
DataContext = new FoosViewModel(Enumerable.Empty<Foo>());
}
private void CollectGarbageClicked(object sender, RoutedEventArgs e)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
你可以在这里得到解释
使用列表会导致强引用(内存泄漏)。简单的解决方案就是将 List
更改为 ObservableCollection
,除非视图(本身)被释放