我将一个Forms
窗口显示为对话框
private void buttonOverview_Click(object sender, EventArgs e)
{
(new OverviewBox()).ShowDialog();
MessageBox.Show("Window Exited");
}
OverviewBox
有一个在构造函数中实例化的刷新计时器
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;
}
});
}
SetDataGridView
将列表设置为itemsource
adatagridview
并显示数据描述。但是,有时我的用户会抱怨异常。异常日志如下所示:
7/15/2013 5:00:10 PM:
System.InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.BeginInvoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.BeginInvoke(Delegate method)
at FormulierGenerator.Views.Agent.OverviewBox.<Poll>b__5()
7/15/2013 5:00:23 PM:
System.InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.BeginInvoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.BeginInvoke(Delegate method)
at FormulierGenerator.Views.Agent.OverviewBox.<Poll>b__5()
7/15/2013 5:00:40 PM:
System.InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.BeginInvoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.BeginInvoke(Delegate method)
at FormulierGenerator.Views.Agent.OverviewBox.<Poll>b__5()
7/15/2013 5:00:53 PM:
System.InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.BeginInvoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.BeginInvoke(Delegate method)
at FormulierGenerator.Views.Agent.OverviewBox.<Poll>b__5()
从异常之间的时间差,我得出结论,至少有两个计时器实例仍然处于活动状态(轮询之间的 30 秒,4 个不同的时间,其中 2 组在 30 秒内,轮询间隔)。但是,我无法通过两次启动和关闭概览来模拟问题。
我怀疑GC
在某个时间点收集窗口对象的相关问题,但轮询器继续存在。当它试图在窗口线程上下文中更新窗口时,它会失败。但是,Window 对象及其所有内容不应该只存在于 private void 的上下文中buttonOverview_Click
吗?为按钮方法添加了 MessageBox.Show() 调用,以测试该方法是否在关闭对话框后完成。它确实显示。
在该方法上设置断点,Poll
以查看在关闭对话框后是否仍调用它。确实如此,因此轮询者的寿命肯定比窗户可见的时间更长。我的问题是,到目前为止我的结论是否正确?如果是这样,即使创建计时器的对象已被实例化的上下文不再存在,轮询器如何继续存在,例如如何防止轮询器在窗口关闭后继续存在?考虑卸载事件操作,但不知道这是否是最佳解决方案。