ObjectDisposedException - running stopwatch in GUI thread
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;
开发者_如何学Go 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;
}
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)?
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.
精彩评论