I have heard that thread cannot access controls of other threads directly.
So our professor gave us a snippet
private void UpdateUI()
{
if(this.InvokeRequired)
this.Invoke(new MethodInvoker(UpdateUI));
else
this.Refresh();
}
and said that InvokeRequired property returns false it the thread is not the owner of the control and then we should call Invoke() method to tell the owner thread to execute UpdateUI() method. Which then updates the UI.
But recently, just out of curiosity I commented InvokeRequired and Invoke()
private void UpdateUI()
{
//if(this.InvokeRequired)
//this.Invoke(new MethodInvoker(UpdateUI));
//else
this.Refresh();
}
and was surprised to see that ThreadPool could access controls of another thread and now I feel that I haven’t completely understood the concept of ThreadPool.
Here’s is the complete code.
using System;
using System.Threading;
using System.Drawing;
using System.Windows.Forms;
class MainForm : Form
{
public MainForm()
{
this.Text = "Hello WinForms";
ThreadPool.QueueUserWorkItem(Clock);
}
private void Clock(object state)
{
for(;;)
{
Thread.Sleep(1000);
UpdateUI();
}
}
private void UpdateUI()
{
//if(this.InvokeRequired)
// this.Invoke(new MethodInvoker(UpdateUI));
//else
this.Refresh();
}
protected override void OnPaint(PaintEventArgs pe)
{
using(Pen pen = new Pen(Color.Red, 2))
pe.Graphics.DrawRectangle(pen, 20, 20, 125, 30);
pe.Graphics.DrawString(DateTime.Now.ToString(), this.Font, Brushes.Blue, 25, 30);
}
[STAThread]
public static void Main()
{
Application.Run(new MainForm());
}
}
Could someone please explain me how does this happen?
Thanks.
In the application you posted, you are not accessing any controls from the ThreadPool, you are only calling Refresh on the form. This actually sends a message to the form to tell itself to redraw itself, but that message is received on the main GUI thread rather than from the ThreadPool thread.
Therefore, you need not Invoke in your case because you do not do any cross thread activity. The OnPaint method gets called indirectly via the windows message pump rather than directly from the Refresh method.
If you were to try and, for example, set the text of a textbox from a background thread… it would throw an exception, and you would be required to use the Invoke pattern to make it work.