This has nothing to do with .net ... but interesting.
Today I realized that no .chm file opened in my computer. It just tried to open the process and they closed without further clues.
Thanks to MJ's Help Diagnostics tool http://www.helpware.net/downloads/MJsDiag.zip
I found, under the HTML Help Run-time Components section this...
File not found: D:\WINDOWS\system32\hhctrl.ocx
I don´t know what the *** happened to this file, but after copying it again, it worked fine.
Wednesday, 29 November 2006
Tuesday, 28 November 2006
Winforms applications, threads and events
Ok here I go with my first entry with a very short sample I wrote for a mate to let him play with threads on winforms, you know... threads are funny!
Windows have a very special way to use threads on winforms as all the controls are bounded to the thread that creates them, so whenever you are going to modify a control´s property, you need to make sure you are doing from the right thread.
A common problem is that you launch a thread to perform async processing and at a certain point, the thread reaches some condition and launches an event.
In the event handler you want to modify some of the user interface properties but... you need to switch to the right thread. That´s where InvokeRequired and Invoke come to help.
InvokeRequired basically compares the thread identity to which the control you are testing is bounded with the thread identity of the running thread. If they are different, it returns true. In that case, you must use Invoke to call a delegate in the right thread.
(Well it´s a little bit more complicated... Invoke can return false if the handle of the control hasn´t been created. If you are in that case, be careful of performing any operation as the control can be created bounded to the wrong thread. Check IsHandleCreated and CreateControl functions to learn more about it...)
By the way... playing with the delays you can realize that if the secondary thread finishes when the main thread is still busy, the invoke sentence is not executed till the main thread is finished. The reason for this is easy: The main thread is running continuosly a loop (you can see it in the call stack window) and the invoke sentence puts a special message to be consumed by that loop.
Only when the loop runs the next iteration, the invoke message is consumed.
Here it comes the mini-sample... copy paste it to a winforms code file to play with it
namespace win_threadDemo
{
public partial class Form1 : Form
{
private delegate void TextDelegate(string text);
private event TextDelegate EventDelegate;
public Form1()
{
InitializeComponent();
this.EventDelegate += new TextDelegate(this.OnEvent);
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "";
label2.Text = "";
if (Thread.CurrentThread.Name == null)
{
Thread.CurrentThread.Name = "Main thread";
}
Thread t = new Thread(new ThreadStart(SecondaryThreadOperation));
t.Name = "Secondary thread";
t.Start();
// Long running operation on main thread
Thread.Sleep(15000);
label2.Text = "Main thread finished";
}
private void SecondaryThreadOperation()
{
//Some long task
Thread.Sleep(10000);
//Raise event if any suscriber is present
if (this.EventDelegate != null)
{
this.EventDelegate("Secondary thread finished");
}
}
private void OnEvent(string text)
{
if (label1.InvokeRequired)
{
label1.Invoke(new TextDelegate(this.ChangeText), new object[] { text });
}
else
{
this.ChangeText(text);
}
}
private void ChangeText(string text)
{
label1.Text = text + " modified on " + Thread.CurrentThread.Name;
}
}
}
Windows have a very special way to use threads on winforms as all the controls are bounded to the thread that creates them, so whenever you are going to modify a control´s property, you need to make sure you are doing from the right thread.
A common problem is that you launch a thread to perform async processing and at a certain point, the thread reaches some condition and launches an event.
In the event handler you want to modify some of the user interface properties but... you need to switch to the right thread. That´s where InvokeRequired and Invoke come to help.
InvokeRequired basically compares the thread identity to which the control you are testing is bounded with the thread identity of the running thread. If they are different, it returns true. In that case, you must use Invoke to call a delegate in the right thread.
(Well it´s a little bit more complicated... Invoke can return false if the handle of the control hasn´t been created. If you are in that case, be careful of performing any operation as the control can be created bounded to the wrong thread. Check IsHandleCreated and CreateControl functions to learn more about it...)
By the way... playing with the delays you can realize that if the secondary thread finishes when the main thread is still busy, the invoke sentence is not executed till the main thread is finished. The reason for this is easy: The main thread is running continuosly a loop (you can see it in the call stack window) and the invoke sentence puts a special message to be consumed by that loop.
Only when the loop runs the next iteration, the invoke message is consumed.
Here it comes the mini-sample... copy paste it to a winforms code file to play with it
namespace win_threadDemo
{
public partial class Form1 : Form
{
private delegate void TextDelegate(string text);
private event TextDelegate EventDelegate;
public Form1()
{
InitializeComponent();
this.EventDelegate += new TextDelegate(this.OnEvent);
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "";
label2.Text = "";
if (Thread.CurrentThread.Name == null)
{
Thread.CurrentThread.Name = "Main thread";
}
Thread t = new Thread(new ThreadStart(SecondaryThreadOperation));
t.Name = "Secondary thread";
t.Start();
// Long running operation on main thread
Thread.Sleep(15000);
label2.Text = "Main thread finished";
}
private void SecondaryThreadOperation()
{
//Some long task
Thread.Sleep(10000);
//Raise event if any suscriber is present
if (this.EventDelegate != null)
{
this.EventDelegate("Secondary thread finished");
}
}
private void OnEvent(string text)
{
if (label1.InvokeRequired)
{
label1.Invoke(new TextDelegate(this.ChangeText), new object[] { text });
}
else
{
this.ChangeText(text);
}
}
private void ChangeText(string text)
{
label1.Text = text + " modified on " + Thread.CurrentThread.Name;
}
}
}
Subscribe to:
Comments (Atom)