Introduction
You might have wanted to execute several codes concurrently on Windows Forms, but you may encountered the Cross-Thread Operation error or faced your application in a dead mood. There are several ways of preventing the application from hanging. Here, I just want to show a simple way to beginners of how it is easy to achieve such a goal in a very straightforward way.
A couple of months ago, I wanted to start ProgressBar while at the same time doing something else within my application. So, the idea of multi-threading came up. Surely you have to separate the tasks using thread philosophy and also get the application away from hanging. I found some useful articles on the net that allowed me to complete my task successfully. Now I just want to disclose this little experience with those who have the same problem.
Here are some helpful links that I used:
Into the Code
First of all, we define a thread variable in the body of the class. We want it to be global because of further changing on it.
using System.Threading;
...
public Thread thread = null;
Delete
Here is the main part for performing our aim. This is contrived in the Delete button. As you see below, first we have defined the thread variable as a global one. For stopping and starting this thread later on, the pause/continue button is used. In our sample in the Delete button, we really don't delete files in the path browsed by the user. It is just a demo for depicting something like that (concurrent code execution is far more important).
private void Btn_Delete_Click(object sender,EventArgs e)
{
if(textBox1.Text ==String.Empty)
{
MessageBox.Show("Please specify a path");
return;
}
Btn_Pause.Enabled = true;
Btn_Stop.Enabled = true;
Btn_Delete.Enabled = false;
InitializeMyObjects();
GetAllFiles();
thread = new Thread(delegate()
{
for(int i = 0; i < files.Count; i++)
{
this.BeginInvoke((ThreadStart)delegate()
{
this.Text = files[i].ToString().Substring(files[i].LastIndexOf(
'\\') + 1);
this.label2.Text = Convert.ToString(i + 1);
progressBar1.PerformStep();
});
Thread.Sleep(6);
}
this.BeginInvoke((ThreadStart)delegate()
{
this.Btn_Pause.Enabled = false;
this.Btn_Stop.Enabled = false;
});
this.BeginInvoke((ThreadStart)delegate()
{
this.ShowMessageDelegate("100% (Process Compeletd)");
});
});
thread.Start();
MessageBox.Show("Am being displayed while progressbar is being performed....");
}
Pause/Continue
The Pause button also acts as a Continue button for continuing and pausing the thread.
private void Btn_Pause_Click(object sender,EventArgs e)
{
if(thread ==null || !thread.IsAlive)
{
MessageBox.Show("Process has not been started or just being finished");
return;
}
if(Btn_Pause.Text.ToUpper() == "pause".ToUpper())
{
Btn_Pause.Text = "Continue";
thread.Suspend();
}
else
{
Btn_Pause.Text = "Pause";
thread.Resume();
}
}
Stop
For stopping a thread, you have to check whether this thread is being suspended or not. If so, make it resume and then abort it. Here, we also implement the rolling back of the progress bar in a new thread.
private void Btn_Stop_Click(object sender,EventArgs e)
{
if(thread.IsAlive)
{
if(thread.ThreadState ==ThreadState.Suspended)
{
thread.Resume();
}
thread.Abort();
label2.Text = "THIS PROCESS OF DELETING HAS BEEN ABORTED";
label2.Refresh();
new Thread(delegate()
{
int val = this.progressBar1.Value;
for(int i = 1; i <= val; Interlocked.Increment(ref i))
{
this.BeginInvoke((ThreadStart)delegate()
{
progressBar1.Increment(-1);
});
Thread.Sleep(10);
}
}).Start();
}
else
label2.Text = "PROCESS HAS BEEN ABORETD";
Btn_Pause.Enabled =false;
Btn_Delete.Enabled =false;
Btn_Pause.Text ="Pause";
Btn_Stop.Enabled =false;
return;
}
Points of Interest
When I made the progress bar run, I noticed that I couldn't drag the form because it hung. So, I began multi-threading for that aim. I used this code for accessing the objects in the same Windows Form by a new thread. When I first created the new thread and then wanted to call a void function for starting some tasks associated with the objects in my form, I got error the error, "Cross-thread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on."
Of course, even in this way if you use objects (write on/modify an object) other than the objects in the new thread — or you have created within the main thread of the application — you will again get this error. You have to use it under the this.BeginInvoke((ThreadStart)delegate(){//implement your logic here...});
part and make the whole new thread start.
Conclusion
All in all, as I mentioned in the introduction, there would be several ways to do this. I used this way because I think it is easy to understand the relevant conceptions and is also very straightforward. By the way, I'd like to ask you to be lenient with my article because it is my first article on the Code Project.
History
- 26 September, 2007 -- Original version posted