When we try to access a control from another thread, you may see an exception, saying 'InvalidOperationException'. Like below
This is raised because a control was accessed without invoking.
One method is to check if that particular object required to be invoked.
If it needs to be invoked, Invoke it else just access it.
A simple way to do this is described in this post.
First Add these references in your code
using System.Threading;
|
Declare two delegates as given below
private delegate void DSetText(string txt);
private delegate void DSetEnable(Control control, bool enable);
|
Define the function to change the text of a control as below
private void SetText(string text)
{
//check
if the label needs to be invoked
if (lblText.InvokeRequired)
{
//create
an object of the delegate. The argument is the method (SetText) itself
DSetText d = new DSetText(SetText);
//now
lets invoke it. pass the arguments of the method as an object array
this.Invoke(d, new object[] { text });
}
else
{
//no
invoke required so lets set the text
lblText.Text = text;
//sometimes
the label needs to be refreshed to view the changed text
lblText.Refresh();
}
}
|
Define the function to enable/disable a control as below
private void SetEnable(Control control,bool enable)
{
//check
if the control needs to be invoked
if (control.InvokeRequired)
{
//create
an object of the delegate the argument is the method (SetText) itself
DSetEnable d = new DSetEnable(SetEnable);
//now
lets invoke it. pass the arguments of the method as an object array
this.Invoke(d, new object[] { control,enable });
}
else
{
//no
invoke required so lets enable/disable the control
control.Enabled = enable;
}
}
|
Declare an object of the Thread. This is the thread where a time consuming work executes
Thread myThread = null;
|
Declare a variable to stop execution of the thread. When this value is True then thread stops execution.
bool StopRequested = false;
|
Define a function to execute in the thread (myThread)
public void StartRunning()
{
int count = 0;
//disable
the start button
SetEnable(btnStart, false);
//enable
stop button
SetEnable(btnStop, true);
//execute
until StopRequested is true. StopRequested is set when btnStop is clicked.
while(!StopRequested)
{
//set
the count as label's text
SetText(count.ToString());
//lets
wait for some time
Thread.Sleep(100);
count++;
}
//enable
the start button
SetEnable(btnStart, true);
//disable
stop button
SetEnable(btnStop, false);
}
|
Now on the Click event of the button( Button to start the thread) add the below code
StopRequested = false;
myThread = new Thread(new ThreadStart(StartRunning));
myThread.Start();
|
Now on the Click event of the other button( Button to stop the thread execution)
StopRequested = true;
|
The overall code is given below
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace ThreadSafeApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//Delegate to set the text
private delegate void DSetText(string txt);
//delegate to enable/disable a control
private delegate void DSetEnable(Control control, bool enable);
//Method to set the text of label
private void SetText(string text)
{
//check if the label needs to be invoked
if (lblText.InvokeRequired)
{
//create an object of the delegate. The argument is the method (SetText) itself
DSetText d = new DSetText(SetText);
//now lets invoke it. pass the arguments of the method as an object array
this.Invoke(d, new object[] { text });
}
else
{
//no invoke required so lets set the text
lblText.Text = text;
//sometimes the label needs to be refreshed to view the changed text
lblText.Refresh();
}
}
private void SetEnable(Control control,bool enable)
{
//check if the control needs to be invoked
if (control.InvokeRequired)
{
//create an object of the delegate. The argument is the method (SetText) itself
DSetEnable d = new DSetEnable(SetEnable);
//now lets invoke it. pass the arguments of the method as an object array
this.Invoke(d, new object[] { control,enable });
}
else
{
//no invoke required so lets enable/disable the control
control.Enabled = enable;
}
}
//thread
Thread myThread = null;
bool StopRequested = false;
public void StartRunning()
{
int count = 0;
//disable the start button
SetEnable(btnStart, false);
//enable stop button
SetEnable(btnStop, true);
//execute until StopRequested is true.
//StopRequested is set when btnStop is clicked.
while(!StopRequested)
{
//set the count as label's text
SetText(count.ToString());
//lets wait for some time
Thread.Sleep(100);
count++;
}
//enable the start button
SetEnable(btnStart, true);
//disable stop button
SetEnable(btnStop, false);
}
private void btnStart_Click(object sender, EventArgs e)
{
StopRequested = false;
myThread = new Thread(new ThreadStart(StartRunning));
myThread.Start();
}
private void btnStop_Click(object sender, EventArgs e)
{
StopRequested = true;
}
}
}
|
Comments
Post a Comment