我正在使用一个计时器,有时当我关闭表单时,我遇到了
崩溃System.Windows.Forms.dll中出现“System.ObjectDisposedException”类型的异常但未在用户代码中处理
附加信息:无法访问已处置的对象。“
这是代码的一部分:
void _PersonUnlimitedTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (exiting)
return;
string time = person.TimerTime;
if (lblTime.InvokeRequired)
{
lblTime.Invoke(new Action(() => lblTime.Text = time));
}
else
{
lblTime.Text = time;
}
}
当我关闭表格
时,我也有这个private void Timers_FormClosing(object sender, FormClosingEventArgs e)
{
if (MessageBox.Show("Are you sure you want to close?", "Close Timer", MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button2) == DialogResult.No)
{
e.Cancel = true;
}
else
{
person.PersonTimer.Stop();
person.PersonTimer.Elapsed -= _PersonUnlimitedTimer_Elapsed;
}
}
我已经多次完成了调试,问题有时候,当我关闭表格时已经输入的程序
if (lblTime.InvokeRequired)
所以程序将执行这部分
lblTime.Invoke(new Action(() => lblTime.Text = time));
但表单已经关闭,导致异常。
我不知道如何解决这个问题。有人能帮我吗?我不希望try catch
这样,因为编码不好:
void _PersonUnlimitedTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (exiting)
return;
try
{
string time = person.TimerTime;
if (lblTime.InvokeRequired)
{
lblTime.Invoke(new Action(() => lblTime.Text = time));
}
else
{
lblTime.Text = time;
}
}
catch
{
}
}
答案 0 :(得分:2)
看起来你正在使用一个在非gui线程上调用回调的计时器,因此需要编组回GUI线程。这可能会使您遇到线程和gui-thread之间的竞争条件。
而是使用Winforms计时器类System.Windows.Forms.Timer。它将在gui线程上调用回调,因此您不会同时运行两个不同的线程。
答案 1 :(得分:0)
我不明白为什么try/catch
编码不好,但你可以这样做:
void _PersonUnlimitedTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (exiting)
return;
// CHECK IF FORM IS ALREADY DISPOSED
if (IsDisposed) return;
string time = person.TimerTime;
if (lblTime.InvokeRequired)
//...
IsDisposed
告诉您Form
是否已被处置。
但这也不是完全线程安全的。 Form
可以放在if
和Invoke
之间。
你使用什么样的Timer
? System.Threading.Timer
或Windows.Forms.Timer
?
假设从方法名_PersonUnlimitedTimer_Elapsed
开始,您使用Threading.Timer
。你不能使用Windows.Forms.Timer
吗?后者负责调用自己,应该有这些问题。
如果您因任何原因无法使用Forms.Timer
,则最后需要使用try/catch
。这不是“编码错误”,它是一种特殊错误处理的好方法。
答案 2 :(得分:0)
我会像我在主题
中所说的那样保留try catchvoid _PersonUnlimitedTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (exiting)
return;
try
{
string time = person.TimerTime;
if (lblTime.InvokeRequired)
{
lblTime.Invoke(new Action(() => lblTime.Text = time));
}
else
{
lblTime.Text = time;
}
}
catch
{
}
}