无法访问已处置的对象

时间:2010-01-13 19:02:00

标签: c# winforms timer

无法访问已处置的对象

任何人都知道为什么我会在这行代码

上收到此错误“无法访问已处置的对象”
Invoke(new UpdateTimerDelegate(UpdateTimer), new object[] { null });

点击开始然后接受/拒绝/或关闭表单 - 似乎在关闭表单时发生

重新启动表单时会发生错误

using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TimerTester
{
    public class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void StartOverBtn_Click(object sender, EventArgs e)
        {
            ShowForm2();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ShowForm2();
        }

        private void ShowForm2()
        {
            Form2 f2;

            f2 = new Form2(10000);
            f2.Owner = this;
            switch (f2.ShowDialog())
            {
                case DialogResult.Yes:
                    break;
                case DialogResult.No:
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.StartOverBtn = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // StartOverBtn
            // 
            this.StartOverBtn.Location = new System.Drawing.Point(33, 33);
            this.StartOverBtn.Name = "StartOverBtn";
            this.StartOverBtn.Size = new System.Drawing.Size(75, 23);
            this.StartOverBtn.TabIndex = 0;
            this.StartOverBtn.Text = "Start Over";
            this.StartOverBtn.UseVisualStyleBackColor = true;
            this.StartOverBtn.Click += new System.EventHandler(this.StartOverBtn_Click);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Controls.Add(this.StartOverBtn);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Button StartOverBtn;
    }
}

窗口2

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace TimerTester
{
    public class Form2 : Form
    {
        public Form2(int timeoutSecondsForAcceptCall)
        {
            this.timeoutSecondsForAcceptCall = timeoutSecondsForAcceptCall;
            InitializeComponent();
            tUpdateTimer = new System.Threading.Timer(new System.Threading.TimerCallback(UpdateTimer), null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
        }

        DateTime dtCreate = DateTime.Now;
        int timeoutSecondsForAcceptCall = 99999;
        System.Threading.Timer tUpdateTimer;

        private delegate void UpdateTimerDelegate(object obj);
        void UpdateTimer(object obj)
        {
            if (InvokeRequired == true)
            {
                Invoke(new UpdateTimerDelegate(UpdateTimer), new object[] { null });
            }
            else
            {
                TimeSpan ts = DateTime.Now - dtCreate;
                if (ts.TotalSeconds > timeoutSecondsForAcceptCall)
                {
                    DialogResult = DialogResult.Cancel;
                    return;
                }
                TimeSpan timeleft = TimeSpan.FromSeconds(timeoutSecondsForAcceptCall) - ts;
                label1.Text = FormatTimeSpan(timeleft);
            }
        }

        private string FormatTimeSpan(TimeSpan ts)
        {
            return ((int)ts.TotalMinutes).ToString().PadLeft(2, '0') + ":" + ((int)ts.Seconds).ToString().PadLeft(2, '0');
        }


        private void btnAccept_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Yes;
        }

        private void btnReject_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.No;
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.btnAccept = new System.Windows.Forms.Button();
            this.btnReject = new System.Windows.Forms.Button();
            this.label1 = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // btnAccept
            // 
            this.btnAccept.Location = new System.Drawing.Point(31, 30);
            this.btnAccept.Name = "btnAccept";
            this.btnAccept.Size = new System.Drawing.Size(75, 23);
            this.btnAccept.TabIndex = 0;
            this.btnAccept.Text = "Accept";
            this.btnAccept.UseVisualStyleBackColor = true;
            this.btnAccept.Click += new System.EventHandler(this.btnAccept_Click);
            // 
            // btnReject
            // 
            this.btnReject.Location = new System.Drawing.Point(140, 29);
            this.btnReject.Name = "btnReject";
            this.btnReject.Size = new System.Drawing.Size(75, 23);
            this.btnReject.TabIndex = 1;
            this.btnReject.Text = "Reject";
            this.btnReject.UseVisualStyleBackColor = true;
            this.btnReject.Click += new System.EventHandler(this.btnReject_Click);
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(31, 80);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(35, 13);
            this.label1.TabIndex = 2;
            this.label1.Text = "label1";
            // 
            // Form2
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(240, 117);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.btnReject);
            this.Controls.Add(this.btnAccept);
            this.Name = "Form2";
            this.Text = "Form2";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Button btnAccept;
        private System.Windows.Forms.Button btnReject;
        private System.Windows.Forms.Label label1;
    }
}

3 个答案:

答案 0 :(得分:1)

您的表单由消息循环处理invoke()消息时处理。我不这么认为有办法避免它。你可以检查一下

  if(!yourForm.IsDisposed)
      yourForm.Invoke(...)

但是,由于调用被发布到UI线程,并且当进程表单可能已经被处理时,这可能无法正常工作,您仍然会得到该异常。您必须通过确保调用未发布在已处置或处置的表单上来以某种方式修复您的程序以避免这种情况。这是一个致命错误,您的程序将在此之后退出。我认为通过try {} catch {}来抑制它将不起作用,因为框架在执行catch块时已经开始卸载。

您可以通过两种方式解决问题。 1.从工具箱中删除一个计时器组件,即System.Windows.Forms.Timer并使用它。    Designer会自动将其添加到组件集合中,并在处理表单之前对其进行处理。 2.在表单中手动执行OnDispose(bool处理)并执行

if(disposing)
    yourTimer.Dispose()

所以现在你的计时器在你的表单之前处理掉了,所以在你的表单被处理后不会发布后续的invoke()。

答案 1 :(得分:1)

您会看到此错误,因为您的System.Threading.Timer不是表单的组成部分。因此,当表格关闭时,它不会被处理掉。我建议你改用System.Windows.Forms.Timer。因为这是一个组件,您可以放置​​在Form上,它将与其他表单的组件一起处理(只需将其从设计器中的工具箱中拖出)。

public class Form2 : Form
{
   DateTime dtCreate = DateTime.Now;
   int timeoutSecondsForAcceptCall = 99999;

   public Form2(int timeoutSecondsForAcceptCall)
   {
      this.timeoutSecondsForAcceptCall = timeoutSecondsForAcceptCall;
      InitializeComponent();
      timer1.Interval = 1000;
      timer1.Start();
   }

   private void timer1_Tick(object sender, EventArgs e)
   {
      TimeSpan ts = DateTime.Now - dtCreate;
      if (ts.TotalSeconds > timeoutSecondsForAcceptCall)
      {
         DialogResult = DialogResult.Cancel;
         return;
      }

     TimeSpan timeleft = TimeSpan.FromSeconds(timeoutSecondsForAcceptCall) - ts;
     label1.Text = FormatTimeSpan(timeleft);
   }

   // other code
}

BTW使用System.Windows.Forms.Timer的另一个好处是它是在UI线程上执行的Tick事件处理程序。因此,您无需验证是否需要调用。

答案 2 :(得分:0)

我以前遇到过这个问题。你应该做几件事。

1)关闭程序时,应该删除处理程序和/或关闭计时器退出时运行的计时器或其他代码。您仍然遇到关闭计时器后仍将运行多少计时器处理程序的问题。一种可能的解决方案是在关闭Timer后设置“停止运行”标志。检查处理程序中的标志,如果已设置,则不运行代码。该标志可以是标记为volatile的bool,也可以是使用Interlocked的long,以避免并发问题,特别是如果您的计时器非常短。

2)围绕你的Invoke语句包装一个try / catch,也将一个放在GUI编辑代码中(InvokeRequired == false的部分)。