我有以下XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Label Name="lblTime" FontSize="48" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Window>
代码隐藏是:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += timer_Tick;
timer.Start();
GC.Collect();
}
void timer_Tick(object sender, EventArgs e)
{
lblTime.Content = DateTime.Now.ToLongTimeString();
GC.Collect();
}
}
我知道的一些事实:
在代码隐藏中,MainWindow不会对计时器进行任何引用。在我看来,它应该被销毁,界面不应该再更新,因为我放了一些GC.Collect调用。但似乎它不起作用,因为界面仍在更新,因此,对象仍然存在。
问题是:发生了什么?我错了吗?还是我错过了一些重要的事实?
编辑1 :此代码实际上是我在教程中找到的一个示例,显示了如何使用DispatcherTimer。但是我想知道当垃圾收集开始时会发生什么,这就是为什么我添加那些GC.Collect以便看看会发生什么。感谢我读过的关于.NET GC的大量教程,我知道调用GC.Collect是一个坏主意,除非非常特殊,否则不应该这样做。
答案 0 :(得分:9)
Dispatcher类为活动计时器维护内部List<DispatcherTimer>
。内部Dispatcher.AddTimer()方法添加它,在Start()方法上调用。 RemoveTimer()由Stop()方法调用。
这会让GC看到参考,直到你停止计时器。您只能通过转换 sender 参数在事件处理程序中执行此操作,只能自行获取引用。
请记住,如果您不调用Stop(), 会继续滴答滴答,即使关闭了具有定时器事件处理程序的Window也是如此。如果你不这样做,那么这样的窗口对象就会泄漏,只有你幸运的话,你才会得到一个ObjectDisposedException。