Thread-safe Access to Form Controls
-
I'm trying to create a program to make thread-safe calls to form controls, specifically to instances of ToolStripStatusLabel and ToolStripProgressBar. I ran cross this page when VC# told me I was unsafely calling the control. The problem is those two classes aren't derived from Control and don't have the InvokeRequired property. I tried using the forms' own InvokeRequired but it's not working and I don't know what to do. Anyone have any help?
-
I'm trying to create a program to make thread-safe calls to form controls, specifically to instances of ToolStripStatusLabel and ToolStripProgressBar. I ran cross this page when VC# told me I was unsafely calling the control. The problem is those two classes aren't derived from Control and don't have the InvokeRequired property. I tried using the forms' own InvokeRequired but it's not working and I don't know what to do. Anyone have any help?
// On a background thread
toolStripProgressBar1.Owner.Invoke((ThreadStart)delegate
{
toolStripProgressBar1.Value = 50;
});Rather than using Invoke/BeginInvoke, you might want to use the System.ComponentModel.BackgroundWorker class, which raises events for you on the appropriate thread, handling all the Invoke/BeginInvoke for you.
Tech, life, family, faith: Give me a visit. I'm currently blogging about: Connor's Christmas Spectacular! Judah Himango
-
// On a background thread
toolStripProgressBar1.Owner.Invoke((ThreadStart)delegate
{
toolStripProgressBar1.Value = 50;
});Rather than using Invoke/BeginInvoke, you might want to use the System.ComponentModel.BackgroundWorker class, which raises events for you on the appropriate thread, handling all the Invoke/BeginInvoke for you.
Tech, life, family, faith: Give me a visit. I'm currently blogging about: Connor's Christmas Spectacular! Judah Himango
that's interesting, thanks. I unfortunately got an exception saying not enough arguments were supplied so I added in my arguments for the delegates like this:
_statusbar.Owner.Invoke((ThreadEvent)delegate
{
_statusbar.Text = "test test, started work";
}, new Object[] { this, ThreadEventArgs("test message", 0, TheadStatusType.thread_started) });In my original delegate, I had it declared object, ThreadEventArgs so I guess that's what it wanted. This works, and without the form-side needing a delegate. Is that the best though? With it like this, it requires a status bar to exist in order to work. I liked the idea of triggering an event and the form can receive it if it wants to and deal with it as it sees fit.
-
that's interesting, thanks. I unfortunately got an exception saying not enough arguments were supplied so I added in my arguments for the delegates like this:
_statusbar.Owner.Invoke((ThreadEvent)delegate
{
_statusbar.Text = "test test, started work";
}, new Object[] { this, ThreadEventArgs("test message", 0, TheadStatusType.thread_started) });In my original delegate, I had it declared object, ThreadEventArgs so I guess that's what it wanted. This works, and without the form-side needing a delegate. Is that the best though? With it like this, it requires a status bar to exist in order to work. I liked the idea of triggering an event and the form can receive it if it wants to and deal with it as it sees fit.
I think I found the problem with what I was doing originally, I don't think I was invoking the delegate right. I ran across this page which talks about BeginInvoke. I used the section of code declared as the typical way of using BeginInvoke as my inspiration and got my invoke working pretty well. I thought anyone reading this and interested in a fix might want to know.
-
that's interesting, thanks. I unfortunately got an exception saying not enough arguments were supplied so I added in my arguments for the delegates like this:
_statusbar.Owner.Invoke((ThreadEvent)delegate
{
_statusbar.Text = "test test, started work";
}, new Object[] { this, ThreadEventArgs("test message", 0, TheadStatusType.thread_started) });In my original delegate, I had it declared object, ThreadEventArgs so I guess that's what it wanted. This works, and without the form-side needing a delegate. Is that the best though? With it like this, it requires a status bar to exist in order to work. I liked the idea of triggering an event and the form can receive it if it wants to and deal with it as it sees fit.
Like I said, BackgroundWorker is really want you should look at:
backgroundWorker1.DoWork += MyWorkerFunction;
backgroundWorker1.ProgressChanged += MyProgressReported;
backgroundWorker1.RunWorkerCompleted += MyWorkCompleted;backgroundWorker1.RunAsync(someArgument); // this will fire the DoWork event
void MyWorkerFunction(object sender, DoWorkEventArgs e)
{
// this is event handler is called on the background thread.
...
// report some progress on the UI thread
backgroundWorker1.ReportProgress(99);
...
// When this method finishes, the RunWorkerCompleted event will be fired on the UI thread.
}void MyProgressReported(object sender, ProgressReportedEventArgs e)
{
// this event handler is fired on the UI thread whenever worker.ReportProgress(progressVal, optionalObject) is called
}void MyWorkCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// This event handler is called on the UI thread.
}Tech, life, family, faith: Give me a visit. I'm currently blogging about: Connor's Christmas Spectacular! Judah Himango
-
Like I said, BackgroundWorker is really want you should look at:
backgroundWorker1.DoWork += MyWorkerFunction;
backgroundWorker1.ProgressChanged += MyProgressReported;
backgroundWorker1.RunWorkerCompleted += MyWorkCompleted;backgroundWorker1.RunAsync(someArgument); // this will fire the DoWork event
void MyWorkerFunction(object sender, DoWorkEventArgs e)
{
// this is event handler is called on the background thread.
...
// report some progress on the UI thread
backgroundWorker1.ReportProgress(99);
...
// When this method finishes, the RunWorkerCompleted event will be fired on the UI thread.
}void MyProgressReported(object sender, ProgressReportedEventArgs e)
{
// this event handler is fired on the UI thread whenever worker.ReportProgress(progressVal, optionalObject) is called
}void MyWorkCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// This event handler is called on the UI thread.
}Tech, life, family, faith: Give me a visit. I'm currently blogging about: Connor's Christmas Spectacular! Judah Himango
I looked at BackgroundWorker after you said it and concluded that using it would require a lot of rewiring of my program, more than I was willing to do. However, I do now know it exists and I'll keep it in mind next time around.