Today, it’s time to mention how GUI Threading is done and where the basic problems are.
In this post I describe how to start a Parameterized Thread, implement delegates, Invoke these Delegate Methods with parameters and Invoke delegate Methods without parameters. So, let’s start with the examples..
1. Start some Threads
private int m_threadcount = 10;
public void ThreadStarter()
{
Thread[] t = new Thread[m_threadcount+1];
for (i = 0; i < m_threadcount; i++)
{
t[i] = new Thread(new ParameterizedThreadStart(ThreadMethod));
t[i].Start("ThreadParameter");
}
}
public void ThreadMethod(String p_ThreadParameter) {
// This method runs about 10 Minutes..
while (true) {
if (ListRecursive("C:\\")) {
break;
}
}
}
2. Do some work
Create a Method called ListRecursive, which will do some work. The Thread should lastly be profitable, shouldn’t it?
public void ListRecursive(String p_Directory) {
// do the hard work
while (1) {..}
}
3. Show what is done in your GUI
So what about some GUI interactions inside the Thread, a progressBar or Log Window updater, for example?
For doing this, you need a delegate for your Method, which is actually changing the GUI. If this is given, an Invoke must call the delegate for you.
Note:
It is generally possible to do GUI changes inside ThreadMethod or ListRecursive by Invoking it via delegates.
But if you do so, the GUI will instantly freeze, because of the infinite while loop (depending on how long the Method call takes) !
Therefore it is much better to implement only cheap functions with a runtime of max 1/10s to do the GUI Stuff, so that no freeze should happen.
The following examples show how the implementation should be done correctly.
The lazy developer would do everything in his/her ListRecursive Method, which is actually possible, but its the
Bad way:
/* Method which is called by the Thread with a long runtime,
* has got an own delegate prototype and is invoked by the Form Window */
protected delegate void MethodListRecursive(String p_Directory);
public void ListRecursive(String p_Directory) {
// Invoke for GUI stuff
if (this.InvokeRequired)
{
this.Invoke(new MethodListRecursive(ListRecursive),
new Object[] { p_Directory });
return;
}
// do the hard work
// ..
while (1) {
// Show the directory entries:
txtLog.Text = txtLog.Text + file + Environment.NewLine;
progressBar.Value++;
// ..
}
}
The Thread safe developer, has got his own delegate and MethodInvoker for every GUI change!
Good and well working way:
/* Method, which only adds the Log Message (extremly fast call) */
protected delegate void MethodLog(String p_Message);
public void Log(String p_Message) {
if (this.InvokeRequired)
{
this.Invoke(new MethodLog(Log),
new Object[] { p_Message });
return;
}
txtLog.Text = txtLog.Text + p_Message + Environment.NewLine;
}
/* Method, which only increments the ProgressBar */
public void ProgressPlus() {
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(ProgressPlus));
return;
}
if (progressBar.Value + 1 <= progressBar.Maximum) progressBar.Value++;
}
/* Method which is called by the Thread - has got a long runtime */
public void ListRecursive(String p_Directory) {
// do the hard work
// ..
// Show the directory entries:
// Now we are using an own delegate method, which runs about 1 nano second ;-)
Log(file);
ProgressPlus();
// ..
}