Reputation: 2121
I was reading that example that I am going to post and what I don't understand is this:
They say that if I want to perform an interaction with the GUI it has to be done by the UI thread.In other words: using the .Invoke method of the Controll class. In the example I don't understand why we are using the output.Invoke...
in the GenerateRandomCharacters
method where the output is being changed but in the Toggle()
where the output is also being changed (its color) there is no .Invoke
? Isn't it the same?
public class RandomLetters
{
private static Random generator = new Random(); // for random letters
private bool suspended = false; // true if thread is suspended
private Label output; // Label to display output
private string threadName; // name of the current thread
// RandomLetters constructor
public RandomLetters( Label label )
{
output = label;
} // end RandomLetters constructor
// delegate that allows method DisplayCharacter to be called
// in the thread that creates and maintains the GUI
private delegate void DisplayDelegate( char displayChar );
// method DisplayCharacter sets the Label's Text property
private void DisplayCharacter( char displayChar )
{
// output character in Label
output.Text = threadName + ": " + displayChar;
} // end method DisplayCharacter
// place random characters in GUI
public void GenerateRandomCharacters()
{
// get name of executing thread
threadName = Thread.CurrentThread.Name;
while ( true ) // infinite loop; will be terminated from outside
{
// sleep for up to 1 second
Thread.Sleep( generator.Next( 1001 ) );
lock ( this ) // obtain lock
{
while ( suspended ) // loop until not suspended
{
Monitor.Wait( this ); // suspend thread execution
} // end while
} // end lock
// select random uppercase letter
char displayChar = ( char ) ( generator.Next( 26 ) + 65 );
// display character on corresponding Label
output.Invoke( new DisplayDelegate( DisplayCharacter ),
new object[] { displayChar } );
} // end while
} // end method GenerateRandomCharacters
// change the suspended/running state
public void Toggle()
{
suspended = !suspended; // toggle bool controlling state
// change label color on suspend/resume
output.BackColor = suspended ? Color.Red : Color.LightGreen;
lock ( this ) // obtain lock
{
if ( !suspended ) // if thread resumed
Monitor.Pulse( this );
} // end lock
} // end method Toggle
} // end class RandsomLetters
EDIT: And here it is the actual call:
public partial class GUIThreadsForm : Form
{
public GUIThreadsForm()
{
InitializeComponent();
} // end constructor
private RandomLetters letter1; // first RandomLetters object
private RandomLetters letter2; // second RandomLetters object
private RandomLetters letter3; // third RandomLetters object
private void GUIThreadsForm_Load( object sender, EventArgs e )
{
// create first thread
letter1 = new RandomLetters( thread1Label );
Thread firstThread = new Thread(
new ThreadStart( letter1.GenerateRandomCharacters ) );
firstThread.Name = "Thread 1";
firstThread.Start();
continues...
This is the way Toggle() method is being called:
private void threadCheckBox_CheckedChanged( object sender, EventArgs e )
{
if ( sender == thread1CheckBox )
letter1.Toggle();
else if ( sender == thread2CheckBox )
letter2.Toggle();
else if ( sender == thread3CheckBox )
letter3.Toggle();
} // end method threadCheckBox_CheckedChanged
After a checkbox control is activated in CheckedChanged event and it gets into the Toggle() method
Upvotes: 0
Views: 109
Reputation: 203802
Presumably whatever is calling this class's methods is only ever calling GenerateRandomCharacters
from a non-UI thread, and Toggle
is only ever being called from the UI thread, hence why only GenerateRandomCharacters
needs to explicitly marshal to the UI thread.
You would need to see how these methods are called to verify that.
Upvotes: 1