为什么在退出表单时收到ObjectDisposedException,而它';It’s正在逐渐进入或重新开始项目周
本文关键字:项目 重新开始 It 表单 退出 ObjectDisposedException 而它 为什么 | 更新日期: 2023-09-27 18:30:00
我正在用C#编写一个应用程序,它将显示不同项目的报告,该应用程序允许用户按办公室、团队和项目选择特定项目,或者允许用户循环浏览给定团队的所有项目。
显示单个项目是相当直接的——应用程序只会打开另一个表单并显示相关信息。另一方面,项目周期在计时器上工作,在60000ms之后,应用程序将关闭最后一个表单,然后重新打开另一个表单(每次都会创建一个新的表单对象),同时显示下一个项目。还有另一个计时器,它将在59800ms后淡出窗体。
我遇到的问题是,当用户在退出或退出表单淡入期间试图重新打开项目周期时,它会抛出:
中发生类型为"System.ObjectDisposedException"的异常System.Windows.Forms.dll,但未在用户代码中处理其他信息:无法访问已释放的对象。
此方法中抛出错误:
private async void FadeIn()
{
this.Opacity = 0;
while (this.Opacity < 1.0)
{
await Task.Delay(100);
this.Opacity += 0.05; //exception is thrown on this line
}
this.Opacity = 1;
}
用户按下ESC键退出报告周期,这将触发以下方法:
protected override bool ProcessDialogKey(Keys keyData)
{
if (Form.ModifierKeys == Keys.None && keyData == Keys.Escape)
{
Program.MainForm.cycleTimer.Stop();
Program.MainForm.fadeOutTimer.Stop();
Program.MainForm.currentReport = 0;
Close();
Program.MainForm.forms.Clear();
return true;
}
return base.ProcessDialogKey(keyData);
}
这是项目周期计时器触发的方法:
private void CycleProjects(Object source, ElapsedEventArgs e)
{
if (forms.Count > 0)
{
forms[0].Close();
forms.Clear();
}
int projectCount = projects.Rows.Count;
if (currentReport == projectCount)
{
currentReport = 0;
}
Form2 cycleReport = new Form2();
cycleReport.Project = "AND p.Project = " + projects.Rows[currentReport]["Project"].ToString();
cycleReport.Office = (cmbOffice2.SelectedIndex == 0) ? 1 : 2;
cycleReport.AmberThresholdFrom = Convert.ToInt16(txtAmberFrom.Text);
cycleReport.AmberThresholdTo = Convert.ToInt16(txtAmberTo.Text);
cycleReport.RedThreshold = Convert.ToInt16(txtRed.Text);
forms.Add(cycleReport);
cycleReport.Show();
currentReport++;
}
我试过简单地隐藏表单并允许CycleProjects方法处理表单,但这在同一个地方引发了相同的异常。我还尝试创建一个CancellationTokenSource
,以在退出循环时取消FadeIn方法中的任务,但我没有成功,仍然抛出了异常。
我只是不明白为什么每次调用CycleProjects方法时,当我创建一个新的Form对象时,都会抛出这个异常。
在表单关闭后,计时器似乎仍在尝试访问表单。但不知道为什么。对Stop
的调用应立即停止计时器。但是,MSDN上的示例在Stop
之后调用Dispose
,并且会触发一个Disposed
事件。
我可以看到,在计时器有机会停止之前关闭表单的可能性(超过)理论上的可能性,尤其是在时间间隔很小的情况下,所以如果你等到Disposed
事件触发,你就会知道关闭表单是可以保存的。
将form.Close();
调用移动到timer.Disposed
事件处理程序中。
您应该考虑的另一件事是使用不同的计时器——在处理UI时,System.Timers.Timer
不是最好的计时器。首先,它的解决方案(即两次通话之间的最短时间)并没有那么好。
为了防止出现此错误,并在关闭/处理表单时退出淡入循环,您可以将FadeIn()
方法修改为以下内容:
private async void FadeIn()
{
this.Opacity = 0;
while (this.Opacity < 1.0)
{
await Task.Delay(100);
// Check to see if form is disposed, and if so, exit loop:
if ((this.IsDisposed) || (this.Disposing))
{
return;
}
this.Opacity += 0.05;
}
this.Opacity = 1;
}
这将防止System.ObjectDisposedException在尝试设置已释放窗体的不透明度时抛出。
或者,您可以尝试捕获System.ObjectDisposedException并使用以下模式退出该方法:
try { this.Opacity += 0.05; }
catch (ObjectDisposedException) { return; }