Reputation: 1076
I'm a newbie to C# and multithreading so I apologise if this is a duplicate question but being a novice it appears my question is slightly different to others I have read.
My GUI runs in one (main) thread. It calls a background task (in a dll -- that I am writing too) that runs in a separate thread. The dll has NO knowledge of the GUI (i.e. it cannot reference the GUI class).
Now, say I want to update a progress bar on the GUI based on the status of the dll thread -> What I'm doing is creating an event in the dll that every X per cent will fire and the GUI will subscribe to this event. When the event is fired, the GUI will update the progress bar.
My questions:
Hope you can clarify this for me!
Thanks
Upvotes: 5
Views: 6971
Reputation: 127543
1.-I use that method all the time and yes it will work
2.-Just pass a int to the event handler and the variable will be safe to read. however when you are fireing the event from code do it like this
private void UpdatePercentage(int a)
{
var myEvent = PercentageUpdatedEvent
if(myEvent != null)
myEvent(this, new ProgressBarEventArgs(a));
}
The reason for this is so if the event is unsubcribed between the null check and the calling you won't get a exception.
3.-As everyone else has mentioned you will need to call Invoke as the event will be running on the dll's thread. However with controls it is legal to call a BeginInvoke without a EndEnvoike so the call will be non blocking on the dll's thread.
Here is the pattern I always use
private myClass_OnPercentageUpdatedEvent(object a, ProgressBarEventArgs e)
{
if(progressBar.InvokeRequired)
progressBar.BeginInvoke((Action<object,ProgressBarEventArgs>)myCless_OnPercentageUpdatedEvent, a, e);
else
{
progressBar.Value = e.Value;
}
}
Upvotes: 3
Reputation: 456417
I have on my blog a few different approaches to this problem, with the advantages/disadvantages of each. In summary, I recommend using the Task
class.
Upvotes: 0
Reputation: 32258
If you spin off a thread, you need to create a delegate, that can safely invoke your main thread with the appropriate parameters.
delegate void UpdateDelegate(int val)
void Update(int val)
{
if(this.InvokeRequired())
{
Invoke(new UpdateDeleage(Update),new object[] {val});
return;
}
this.MyProgressBar.Value = val;
}
Call Update from your separate thread as you would if calling it from your main thread. Once the thread determines that your main thread needs invoked to pass the value, it will invoke it with your delegate, with the parameters you passed. Otherwise, it will simply skip the block and set your values.
e.g.
...
new Thread(()=>IncrementValues()).Start();
...
void IncrementValues()
{
while(true)
Update(new Random(0,10));
}
Upvotes: 0
Reputation: 40149
Keep in mind that under most circumstances, the events raised from your background task will also run on the background thread. No thread context switch happens automatically at all.
To understand why, you have to consider what an event is; just a certain type of Delegate
object. You are setting a Delegate to that event from the main thread... but that delegate will actually be called within the background thread, in the code that triggers the event.
So yes; you would need to make sure you are moving things over to run on the GUI thread from within that event handler.
Upvotes: 3
Reputation: 6259
To answer (3) you will need to use Invoke. The event-handlers are going to be run from the background thread, not the GUI thread.
Upvotes: 0
Reputation: 33071
Look into the BackgroundWorker class. It sounds like it fits your scenario pretty well.
This link on MSDN explains how to use it: http://msdn.microsoft.com/en-us/library/cc221403%28VS.95%29.aspx
Upvotes: 3