|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
IntroductionThis article presents a control that creates threads and displays the progress and any messages sent from the thread. BackgroundRunning multiple threads and seeing the status of where they are has been a tricky subject for quite a while. The main thing being that you could not access anything that is being controlled by the main (UI) thread. This includes all parts of the form you are displaying and the properties and variables on it. The .Net framework 2.0 has helped clear up some of that with the introduction of the BackgroundWorker class. This class allows you to run some code on its own thread. This allows your UI to remain responsive while the code runs. What It DoesThis control can be easily modified to be used to monitor/control batch operations that can be done simultaneously. Some examples:
Each thread can send its own messages back to the container. The container shows those messages in a grid as the threads are running. The thread container actually does throttling as well. Before you start the threads, you can set the number of threads you want to run concurrently. I hope to eventually make this property dynamic so that it can be changed on the fly. What It Does Not DoThis control is designed for items that do not update the UI other than what is already displayed. If you need to render objects and update the screen, you will need to modify the way this works. That may be another article. How it WorksEach thread is represented in a ThreadView which inherits from UserControl. This ThreadView contains a BackgroundWorker. When the ThreadContainer.Start method is called it creates as many threads as it can (either Concurrent or TotalThreads if it is less than Concurrent). The ThreadViews are docked to the top so that they are all displayed nicely and expand to the width of the ThreadContainer. After creating the new ThreadView and displays it and starts it. As it works it raises its JobEvent event. This passes the message to the container and the ThreadContainer stores it in its DataTable. Each ThreadView contains a JobCompleted event that notifies the ThreadContainer that it is done. How to Use the CodeI have divided up the code for the control and the test app into two projects. So, if you usually like to look at the code and the forms before running it then THE FIRST THING YOU DO AFTER OPENING THE PROJECT IS BUILD IT OR YOU WILL GET ERRORS because I have stripped out the information to make the download smaller. The ThreadView classCurrently the code sleeps for a random number of milliseconds 100 times. Not terribly useful. Go to the ThreadView class and the worker_DoWork method. You can change this code to do whatever you would like it to do. Here is the code. This I have omitted some of the comments for brevity. private void worker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i= 0; i < 100; i++)
{
//this checks to see if the user pressed the cancel button
if(worker.CancellationPending)
break;
worker.ReportProgress(i, "Progress:" + i.ToString());
try
{
Thread.Sleep(r.Next(0, _maxSleep));
}
catch
{
// You really want to do a better job than I did with error handling
}
OnJobEvent(new JobEventEventArgs(ThreadName, "Progress: " + i.ToString()));
}
}
There are two function calls that you need to worry about
That’s it! Change the code to do what you want it to do and the progress bars and the messages to your messages and you are done! Properties and ConstructorsCurrently I pass the maximum time I would like to the thread to sleep in via a property, but you can define whatever properties you would like, or change the constructor and pass them in as parameters. What you have to do is make sure you pass it into the ThreadContainer as well as the ThreadView classes. Or you can pass a value to the ThreadView (i.e. a DirectoryInfo) and it calculates the values for you (DirectoryInfo.GetFiles().GetUpperBound(0)). Controlling the ThreadView Progress bar maximumCurrently I have it set the bar maximum at 100, but if the number of objects you are working with is not 100 you have 3 options:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||