所以我试图创建一个具有一个新依赖项属性并使用此DP的WPF控件。控件的XAML就像这样简单:
<UserControl x:Class="DPTest.TestControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DPTest">
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=local:TestControl}, Path=TestText}"/>
只是显示新属性的TextBlock。 Codebehind声明了依赖属性,如下所示:
using System.Windows;
namespace DPTest
{
public partial class TestControl
{
public static readonly DependencyProperty TestTextProperty =
DependencyProperty.Register("TestText", typeof(string), typeof(TestControl), new PropertyMetadata(default(string)));
public TestControl()
{
InitializeComponent();
}
public string TestText
{
get => (string) GetValue(TestTextProperty);
set => SetValue(TestTextProperty, value);
}
}
}
到目前为止一切都很好。但是,创建此控件永远不会被GC收集。为了证明这一点,我使用了一个Window,只需在加载时创建大量的TestControl:
using System.Windows;
namespace DPTest
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
while (true)
{
var uc = new TestControl();
}
}
}
}
打开此窗口会显示RAM快速增加,而GC会频繁启动。内存分析显示位于RAM中的TestControl的所有实例。
如果我用常量值替换控件内的绑定,那么就像这样:
<TextBlock Text="hello"/>
RAM不会增加,并且会成功收集未使用的控件实例。
看起来我做错了但是这个例子非常简单和常见,所以我卡住了。请帮忙。
答案 0 :(得分:2)
您正在控制调度程序线程,这会阻止数据绑定引擎执行任何操作。如果我冒险猜测,有些东西正在排队等待由DataBind
调度程序优先级的数据绑定引擎处理,而你的循环正在阻止这种情况发生。
如果你像这样重写它,你仍然会生成无数的测试控件,但你不会看到你的记忆增长:
private void OnLoaded(object sender, RoutedEventArgs e)
{
InstantiateNewControl();
}
private void InstantiateNewControl()
{
var tc = new TestControl();
this.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(InstantiateNewControl));
}
这将为数据绑定引擎提供在每个实例化之间完成一些工作的机会。
如果您注释掉指定DispatcherPriority.Background
的行,您会看到内存再次开始增长。这是因为默认优先级是最高的(Normal
),它优先于布局,输入,数据绑定等。通过以高优先级充斥调度程序,您将阻止其他工作完成。
在使用内存分析器进行调查后,看起来就像内存增长源于BindingExpression
中保持活动的新DataBindManager
实例。具体来说,有一个字典将绑定表达式映射到它们最近的数据绑定操作,看起来你正在阻止该字典被正确维护。新实例化的测试控件上的表达式永远不会被删除。
答案 1 :(得分:0)
这与你的控制毫无关系。你的while循环 在加载的事件中永远运行。垃圾收集器根本无法收集 和创建新控件一样快。
尝试使用foreach循环和几千次迭代 - 至少应该让你开始运行