有时会调用程序崩溃

时间:2016-05-20 08:50:58

标签: c#

我正在使用一个计时器,有时当我关闭表单时,我遇到了

崩溃
  

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 
    {
    }
}

3 个答案:

答案 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可以放在ifInvoke之间。

你使用什么样的TimerSystem.Threading.TimerWindows.Forms.Timer

假设从方法名_PersonUnlimitedTimer_Elapsed开始,您使用Threading.Timer。你不能使用Windows.Forms.Timer吗?后者负责调用自己,应该有这些问题。

如果您因任何原因无法使用Forms.Timer,则最后需要使用try/catch。这不是“编码错误”,它是一种特殊错误处理的好方法。

答案 2 :(得分:0)

我会像我在主题

中所说的那样保留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 
    {
    }
}