I have a multi-threaded application where each thread has the ability to log pending GUI updates by utilizing a shared (and thread safe) BlockingCollection that contains guiUpdateObjects
.
Each guiUpdateObject
contains information on which control to update and the content to be displayed. I'd like to have my Form consume any items that exist on that BlockingCollection
and update the various controls accordingly.
This set up worked well for me previously in the Java version of this application where after spawning threads and doing initialization tasks, the main thread checked for items on a timed loop.
I suppose I could do the same in C# with a timer event but given all the native event handling in Windows Forms, I'm wondering if there's a better way. Perhaps, with a custom event? Would appreciate any criticisms on my current approach and/or suggestions on how best to implement this in C#.
Update based on Hans suggestion:
After reading up on Control.BeginInvoke(), I understand that this will allow me to PostMessage to the application message queue. This is similar to my utilization of BlockingCollection in that it's thread safe and immediately returns without waiting for the message to be processed.
However, utilizing BeginInvoke requires using delegates and after reading up on them, I'm still a bit confused on proper implementation. Do I declare the delegate in my Form class or in the 'worker' class that will be generating content for gui updates? If I declare in my Form class, the method won't be visible to my worker class unless I reference the Form object. Alternatively, if I declare in the worker class, how will the Form class make the association between the delegate method and the actual method? Here's some code highlighting my question:
public partial class GUI : Form
{
public GUI()
{
InitializeComponent();
Thread workerThread = new Thread(new ThreadStart(new Worker().DoWork));
workerThread.Start();
}
private delegate void AppendSysLogDelegate(string logEntry);
private void AppendSysLog(string logEntry)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new AppendSysLogDelegate(AppendSysLog), new object[] { logEntry });
return;
}
systemLogger.AppendText(logEntry);
}
}
public class Worker
{
public void DoWork()
{
//what goes here to call AppendSysLog("Test log entry");
}
}