C# 计时器对象存在于窗口对象生存期之外

C# 计时器对象存在于窗口对象生存期之外,c#,C#,我正在将一个窗体窗口显示为对话框 private void buttonOverview_Click(object sender, EventArgs e) { (new OverviewBox()).ShowDialog(); MessageBox.Show("Window Exited"); } 概览框有一个在构造函数中实例化的刷新计时器 public OverviewBox() { InitializeComponent(); this._polltim

我正在将一个
窗体
窗口显示为对话框

private void buttonOverview_Click(object sender, EventArgs e)
{
    (new OverviewBox()).ShowDialog();
    MessageBox.Show("Window Exited");
}
概览框
有一个在构造函数中实例化的刷新计时器

public OverviewBox()
{
    InitializeComponent();

    this._polltimer = new Timer { Interval = 30000, Enabled = true };
    this._polltimer.Tick += (sender, e) => { this.Poll(); };
}
方法
Poll
异步从数据库获取数据,并更新视图而不冻结它

private void Poll()
{
    Task.Run(() =>
    {
        if (!SessionContext.Connectable())
        {
            return;
        }
        try
        {
            [logics to get data]
            this.dgvChangeCoordinators.BeginInvoke(new Action(() => { SetDataGridView(this.dataGridView, "<Data Description>", listwithdata); }));
        }
        catch (Exception ex)
        {
            Logger.Log(ex.ToString());
            throw;
        }
    });
}
根据异常之间的时间差,我得出结论,至少有两个计时器实例仍然处于活动状态(轮询之间的时间间隔为30秒,2组在30秒内的4个不同时间,轮询间隔)。但是,我无法通过两次启动和关闭概述来模拟问题

我怀疑有一个
GC
相关的问题,窗口对象在某个时间点被收集,但轮询器仍然存在。当它尝试在窗口线程上下文中更新窗口时,失败。但是,难道窗口对象及其所有内容不应该只存在于私有void
按钮的上下文中吗?向button方法添加了MessageBox.Show()调用,以测试关闭对话框后该方法是否完成。它确实表明了这一点


Poll
方法上设置断点,查看对话框关闭后是否仍调用该方法。是的,所以民意调查者的寿命肯定比窗户还长。我的问题是,到目前为止我的结论正确吗?如果是这样,即使创建计时器的对象已实例化的上下文不再存在,轮询器如何继续存在?例如,如何防止轮询器在窗口关闭后继续存在?正在考虑卸载事件操作,但不知道这是否是最佳解决方案。

需要将勾号转换为命名方法

this._polltimer.Tick += _polltimer_Tick;
并在关闭表单时取消注册

    private void OverviewBox_FormClosed(object sender, FormClosedEventArgs e)
    {
        this._polltimer.Tick -= this._polltimer_Tick;
    }
不注销可防止计时器被销毁,因为仍然存在对它的活动引用。但是,关闭表单会破坏表单上的元素,导致调用invoke时出现问题


非常感谢所有回复@BenjaminBaumann的人,他们提供了导致这个答案的线索。

首先,垃圾收集器不是确定性的。即使您的窗口已关闭且未在任何位置引用,在实际收集该窗口之前可能需要很长时间。您应该取消订阅
勾选
事件,并在窗口关闭后立即将
IsEnabled
设置为
false

话虽如此,这里真正的问题是
System.Windows.Forms.Timer
本身。一旦启用,它就会为自己分配一个内存,防止垃圾收集。然后,事件处理程序阻止收集窗口,而不是像通常情况下那样,以及您认为正在发生的情况


请注意,
System.Windows.Forms.Timer
在释放时会禁用自身,以防止出现此问题,并且
表单的所有组件在表单关闭时都会自动释放。但是您没有将
计时器注册为表单组件,因此
Dispose
永远不会自动调用。您应该通过工具箱向窗体中添加一个
计时器
,或者使用
新计时器(组件)
实例化它,以查看问题是否消失。

BeginInvoke()
不会使您的代码异步。您根本不需要它。您是否尝试过在窗口的“已加载”事件中启动计时器?我认为您错误地认为关闭对话框会杀死OverviewBox对象。你在代码中确认了吗?我认为,即使对话框不再可见,概览框也可能仍然存在,它的计时器。@SLaks BeginInvoke()是从Task.Run创建的线程调用的。据我所知,除了窗口线程之外,不可能从其他线程更新UI。据我所知,我需要在窗口线程中直接调用任何更新窗口的内容。如果我错了,你能详细说明一下吗?注销计时器也会有帮助。关闭概览框时勾选事件。
    private void OverviewBox_FormClosed(object sender, FormClosedEventArgs e)
    {
        this._polltimer.Tick -= this._polltimer_Tick;
    }