Невозможно получить доступ к удаленному объекту - PullRequest
2 голосов
/ 13 января 2010

Невозможно получить доступ к удаленному объекту

Кто-нибудь знает, почему я получаю эту ошибку «Невозможно получить доступ к удаленному объекту» в этой строке кода

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

form2

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 ]

1 голос
/ 21 октября 2012

Вы видите эту ошибку, потому что ваш 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
}

Кстати, еще одним преимуществом использования System.Windows.Forms.Timer является то, что Tick обработчик событий выполняется в потоке пользовательского интерфейса. Таким образом, вам не нужно проверять, требуется ли вызывать.

1 голос
/ 13 января 2010

Ваша форма удаляется по времени, когда сообщение invoke () обрабатывается циклом сообщений. Я не думаю, что есть способ избежать этого. Вы можете поставить чек, например,

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

Но иногда это может не сработать, так как вызов публикуется в потоке пользовательского интерфейса, и к тому времени, когда это форма процесса, уже может быть удалена, и вы все равно получите это исключение. Вы должны исправить свою программу таким образом, чтобы избежать этой ситуации, убедившись, что invoke не размещен на удаленной или утилизируемой форме. Это фатальная ошибка, и ваша программа завершит работу после этого. Я думаю, что подавление его с помощью try {} catch {} не будет работать, так как фреймворк уже начинает выгружаться при выполнении блока catch.

Вы можете решить проблему двумя способами. 1. Просто удалите компонент таймера из набора инструментов, то есть System.Windows.Forms.Timer, и используйте его. Дизайнер автоматически добавит его в коллекцию компонентов и удалит его до удаления формы. 2. Вручную перезапустите OnDispose (удаление bool) в вашей форме и выполните

if(disposing)
    yourTimer.Dispose()

Так что теперь ваш таймер удаляется перед вашей формой, поэтому никакие последующие invoke () не будут опубликованы в вашей форме после ее удаления.

0 голосов
/ 13 января 2010

У меня была эта проблема раньше. Есть пара вещей, которые вы должны делать.

1) Когда вы закрываете свою программу, вы должны удалять обработчики и / или выключать таймеры или другой код, который будет работать при выходе из программы. У вас все еще остается проблема с тем, сколько обработчиков таймера все еще будет работать после выключения таймера. Одним из возможных решений является установка флага «остановить работу» после выключения таймера. Проверьте флаг в обработчике и не запускайте код, если он установлен. Флаг может быть логическим, помеченным как volatile или long, использующим Interlocked, чтобы избежать проблем параллелизма, особенно если ваш таймер очень короткий.

2) Оберните попытку / зацепку вокруг вашего оператора Invoke, также поместите его в код редактирования графического интерфейса (часть, где InvokeRequired == false).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...