In this tutorial we will be using multiple threads (multi-threading) and showing the benefits of doing so, and also the impracticalities.

We are going to create a small form containing a button, a progressbar and a label, and use these objects to display the output of intensive work, whilst still maintaining a useable GUI that does not lock-up as a result of the hard work.

This one is a toughie to explain. I hope I managed to explain it clearly enough.
Again, its fully useable, you can copy/paste it right in.

PHP Code: 
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;

namespace 
WindowsFormsApplication4
{
    public 
partial class Form1 Form
    
{
        public 
Form1()
        {
            
InitializeComponent();
        }

        
// Here we declare that "StatusInfo" will be our delegated void to use in our thread.
        // We also declare 3 required variables: status, progress, and MaxProgress.
        // We are declaring it here, so all "voids" can make use of it, not just the "void"
        // it was created in.
        
private delegate void StatusInfo(string statusint progressint MaxProgress);

        private 
void Form1_Load(object senderEventArgs e)
        {
            
            
// Set the form size
            
this.Size = new Size(340150);
            
            
CreateSomeObjects();
        }

        private 
void CreateSomeObjects()
        {
            
// Button - myButton1
            
Button Button1 = new Button(); // Declare a new button, and give it a unique ID
            
Button1.Name "myButton1"// Give it a name (we will be using this later)
            
Button1.Size = new Size(10023); // Set the size
            
Button1.Location = new Point(1010); // Set the location on the form
            
Button1.Text "Click Me"// Set the text for the button
            
Button1.Click += new EventHandler(letsPlay); // Set the click event (what to execute when clicked)

            // ProgressBar - myProgress1
            
ProgressBar ProgressBar1 = new ProgressBar();
            
ProgressBar1.Name "myProgress1";
            
ProgressBar1.Size = new Size(30023);
            
ProgressBar1.Location = new Point(1043);
            
ProgressBar1.Minimum 0// The minimum value of the progressbar
            
ProgressBar1.Maximum 100// The maximum Value of the progressbar
            
ProgressBar1.Value 0// The current position of the progressbar

            // Label - myLabel1
            
Label Label1 = new Label();
            
Label1.Name "myLabel1";
            
Label1.AutoSize true;
            
Label1.Location = new Point(1076);
            
Label1.Text "Ready.";

            
// Draw the objects on the current Form (this)
            
this.Controls.Add(Button1);
            
this.Controls.Add(ProgressBar1);
            
this.Controls.Add(Label1);
        }


        private 
void letsPlay(object senderEventArgs e)
        {
            
// Here we get interesting. We create a new seperate thread, seperate from the main thread.
            // We are doing this because we dont want our GUI to lock-up whilst processing this
            // heavy loop (simulated by making the thread sleep).
            
            // So here we declare the new thread, and tell it to execute "MoveProgress".
            
System.Threading.Thread myThread = new System.Threading.Thread(MoveProgress);
            
            
// Kickoff time :D - go go go!
            
myThread.Start();
        }

        private 
void MoveProgress()
        {
            
// We are going to set our delegated void as a NEW delegate, and that it should look to
            // "DisplayStatus" to pass the values. The void "DisplayStatus" will have the same required
            // variables that we described at the beginning: status, progress, and MaxProgress.
            
StatusInfo StatusInfo = new StatusInfo(DisplayStatus);

            
// Ok - so lets simulate some heave work by forcing this thread to sleep for 50 milliseconds
            // after every loop.

            // Notice the use of a StringBuilder. Its no use here really, and TERRIBLE practice to put
            // it in the loop like i have, but for the sake of learning, you can easily see how to
            // use a StringBuilder, and obviously, how it could be of use in large applications.
            // NOTE: You can "Append" to the existing data, or "AppendLine" to add a new line of data.
            
            
for (int i 0101i++)
            {
                
StringBuilder sb = new StringBuilder(); // Declare a new instance of a stringBuilder called sb
                
sb.Append("Loading: "); // Append to the existing text (currently zero-length)
                
sb.Append(i); // and again...
                
sb.Append(" of 100"); // and again
                
                // Finally we get to the point where we need to "output" this information we have obtained.
                // In our example we are going to use both a ProgressBar and a label to do so.
                // So we "Invoke" the forum. Kinda like an "oi, something needs to be done, wake up" call.
                // We are Invoking the delegate StatusInfo, and passing the required variables as declared
                // When we made the instance of it at the beginning: status, progress, and MaxProgress.
                // So, we use the contents of the stringBuilder "sb" for the status, and convert it to a
                // string (because currently its a StringBuilder, not a string)
                // And for this example we will pass the integer i as the progress, with a maximum of 100.

                
Invoke(StatusInfosb.ToString(), i100); 
                
System.Threading.Thread.Sleep(50);
            }
        }

        private 
void DisplayStatus(string statusint progressint maxProgress)
        {
            
            
// The following code is VERY interesting and useful.
            // When we created our objects (button, ProgressBar and label) - we did so without the use
            // of the designer. This means when the form loads, nothing is there. The objects are created
            // AFTER the form loads. So, if we try to modify one of its properties in this code, its not
            // going to be visible. So we need to find these controls and again assign them a unique ID
            // so we can manipulate them for our required purposes; displaying our output.

            
ProgressBar myFoundProgressBar = new ProgressBar();
            
Label myFoundLabel = new Label();

            foreach (
Control myControl in this.Controls// foreach control in my form
            
{
                if (
myControl.Name == "myProgress1"// if the controls name is "myProgress1"
                    
myFoundProgressBar = (ProgressBar)myControl// Then assign it to the ID "myFoundProgressBar"
                
if (myControl.Name == "myLabel1"// We do the same here for the label.
                    
myFoundLabel = (Label)myControl;
            }

            
// Now we are able to manipulate these controls using the data we obtained when we invoked it.
            
myFoundLabel.Text status;
            
myFoundProgressBar.Maximum maxProgress;
            
myFoundProgressBar.Value progress;
        }

        
// OK. so we need to understand something here. Why invoke? Why use a seperate thread? It seems like
        // a whole bunch of hard work, just to display an output!
        // Well. There is one important factor:
        // You cannot manipulate an object using a thread IF THAT THREAD DID NOT CREATE THE OBJECT.
        // And its right. The thread myThread DID NOT create the button or anything else for that matter.
        // The PRIMARY thread did.
        // So, to get around this, we "invoke". This basically allows you to pass variables back to the
        // Primary thread, where everything was created in the first place, and thus manipulate the controls,
        // Whilst still being able to throw the hard work in a seperate thread, and thus not lock-up the main
        // thread (which is home to the GUI)
        // So what does this all mean? It means that your GUI will not lock up, because a secondary thread,
        // NOT the primary thread is doing all the work, and every now and again, you invoke the primary thread
        // to update the GUI.
    
}

jayfella Reviewed by jayfella on . [c#] Multi-Threading and keeping the GUI useable. In this tutorial we will be using multiple threads (multi-threading) and showing the benefits of doing so, and also the impracticalities. We are going to create a small form containing a button, a progressbar and a label, and use these objects to display the output of intensive work, whilst still maintaining a useable GUI that does not lock-up as a result of the hard work. This one is a toughie to explain. I hope I managed to explain it clearly enough. Again, its fully useable, you can Rating: 5