ObjectDisposeException - 在 GUI 线程中运行秒表

发布于 2024-08-18 06:41:15 字数 1225 浏览 13 评论 0原文

我有一个在不同线程中运行的秒表,它更新标签中的 GUI 线程以随着时间的推移而显示。当我的程序关闭时,当我在 Form GUI 中调用 this.Invoke(mydelegate); 以使用秒表中的时间更新标签时,它会抛出 ObjectDisposeException

我如何摆脱这个ObjectDisposeException

我试图在 FormClosing 事件中停止秒表,但它无法处理它。

这是代码:

System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            stopwatch = sw;

            sw.Start();
            //System.Threading.Thread.Sleep(100);
            System.Threading.Thread t = new System.Threading.Thread(delegate()
            {
                while (true)
                {
                TimeSpan ts = sw.Elapsed;

                string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                ts.Hours, ts.Minutes, ts.Seconds,
                ts.Milliseconds / 10);

                timeElapse = elapsedTime;

                  UpdateLabel();
                }
            });
            stopwatchThread = t;
            t.Start();

 public void UpdateLabel()
        {
            db = new doupdate(DoUpdateLabel);

            this.Invoke(db);
        }

 public void DoUpdateLabel()
        {
            toolStripStatusLabel1.Text = timeElapse;
        }

I have a stopwatch running in a different thread, that updates the GUI thread in a label to show as time goes by. When my program closes, it throws a ObjectDisposedException when I call this.Invoke(mydelegate); in the Form GUI to update the label with the time from the stopwatch.

How do I get rid of this ObjectDisposedException?

I have tried to stop the stopwatch in the FormClosing Event, but it does not handle it.

Here's the code:

System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            stopwatch = sw;

            sw.Start();
            //System.Threading.Thread.Sleep(100);
            System.Threading.Thread t = new System.Threading.Thread(delegate()
            {
                while (true)
                {
                TimeSpan ts = sw.Elapsed;

                string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                ts.Hours, ts.Minutes, ts.Seconds,
                ts.Milliseconds / 10);

                timeElapse = elapsedTime;

                  UpdateLabel();
                }
            });
            stopwatchThread = t;
            t.Start();

 public void UpdateLabel()
        {
            db = new doupdate(DoUpdateLabel);

            this.Invoke(db);
        }

 public void DoUpdateLabel()
        {
            toolStripStatusLabel1.Text = timeElapse;
        }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

二智少女猫性小仙女 2024-08-25 06:41:15

看起来是当您关闭应用程序时秒表正在被释放,但线程仍在运行并尝试使用它。您可以在关闭应用程序之前(在 FormClosing 事件中)先停止线程吗?

What it looks like is the Stopwatch is being disposed when you close your application, but the thread is still running and trying to use it. Can you stop your thread first before closing the application (in the FormClosing event)?

江南烟雨〆相思醉 2024-08-25 06:41:15

相同的代码,现在使用BackgroundWorker和有序关闭,确保在后台线程首先停止运行之前表单不会关闭:

using System;
using System.Threading;
using System.Windows.Forms;
using System.Diagnostics;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
            backgroundWorker1.DoWork += backgroundWorker1_DoWork;
            backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
            backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
            backgroundWorker1.WorkerReportsProgress = backgroundWorker1.WorkerSupportsCancellation = true;
            backgroundWorker1.RunWorkerAsync();
        }
        bool mCancel;
        void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) {
            if (e.Error != null) MessageBox.Show(e.Error.ToString());
            if (mCancel) this.Close();
        }
        protected override void OnFormClosing(FormClosingEventArgs e) {
            if (backgroundWorker1.IsBusy) mCancel = e.Cancel = true;
            backgroundWorker1.CancelAsync();
        }
        void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) {
            label1.Text = e.UserState as string;
        }
        void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) {
            Stopwatch sw = Stopwatch.StartNew();
            while (!backgroundWorker1.CancellationPending) {
                TimeSpan ts = sw.Elapsed;
                string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                    ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
                backgroundWorker1.ReportProgress(0, elapsedTime);
                Thread.Sleep(15);
            }
        }
    }
}

请注意,需要Sleep()调用,不可能将调用编组到UI线程每秒超过约1000次。

Same code, now using a BackgroundWorker and an orderly shutdown that ensures the form doesn't close until the background thread has stopped running first:

using System;
using System.Threading;
using System.Windows.Forms;
using System.Diagnostics;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
            backgroundWorker1.DoWork += backgroundWorker1_DoWork;
            backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
            backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
            backgroundWorker1.WorkerReportsProgress = backgroundWorker1.WorkerSupportsCancellation = true;
            backgroundWorker1.RunWorkerAsync();
        }
        bool mCancel;
        void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) {
            if (e.Error != null) MessageBox.Show(e.Error.ToString());
            if (mCancel) this.Close();
        }
        protected override void OnFormClosing(FormClosingEventArgs e) {
            if (backgroundWorker1.IsBusy) mCancel = e.Cancel = true;
            backgroundWorker1.CancelAsync();
        }
        void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) {
            label1.Text = e.UserState as string;
        }
        void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) {
            Stopwatch sw = Stopwatch.StartNew();
            while (!backgroundWorker1.CancellationPending) {
                TimeSpan ts = sw.Elapsed;
                string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                    ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
                backgroundWorker1.ReportProgress(0, elapsedTime);
                Thread.Sleep(15);
            }
        }
    }
}

Note that the Sleep() call is required, it isn't possible to marshal calls to the UI thread more than about a 1000 times per second.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文