Click here to Skip to main content
15,881,812 members
Articles / Desktop Programming / Windows Forms
Article

Using Events and Threading to Communicate Long Processes to UI

,
Rate me:
Please Sign up or sign in to vote.
3.00/5 (10 votes)
12 Dec 2008GPL32 min read 33.6K   415   46   6
Using events and threading to communicate long processes to UI
UI_Illustration_LongProcess.JPG

Introduction

Sometimes it is necessary to communicate or “send” information from a long data process to User Interface (UI) in order to let the user know how it is going.

Due to the fact that it is recommended to separate logic or database work from UI, this situation becomes complicated to solve without mix (or mess?) layers.

Here it is important to use events inside the big and long process in order to let the UI know the progress of the actions, without mixing layers.

Background

It’s better to be familiarized with threads, delegates and events before to implement this suggestion to your projects.

Using the Code

The Visual Studio solution in this example uses two projects, one to simulate databases work (or any other long process) and a different project for UI with two forms. The first one is for simulating the application itself and the second one for process informing. Both projects are in different assemblies, the long process is a DLL with different namespace from UI that is the main EXE.

In the long process, probably inside a for or a foreach, add the instruction to rise the event, "sending" to UI the information that will be necessary to notify the user about any progress.

C#
public void BigProcess()
{
    float x = 0;
    float Limit = 150;

    for (int i = 0; i <= Limit; i++)
    {
        x = (i / Limit) * 100;
        //Rise the event
        ProgressStatus(new ProgressEventArgs(Convert.ToInt32(x), i.ToString(), x));
        Thread.Sleep(100); //Simulating some processes here
    }
}

Then in the UI, it is necessary to instantiate the form that will be used to inform the user about the progress of the process. But, for better performance, it is necessary to “split” the work using threads.

UI1.JPG

C#
private void button1_Click(object sender, EventArgs e)
{
    //Use other thread for DB work  
    ThreadPool.QueueUserWorkItem(new WaitCallback(DBWork));
    //show the progress form
    frmProgr.ShowDialog();
}

private void DBWork(object o)
{
    DBprocess dst = new DBprocess();
            
    //Subscribe to event
    dst.ProgressStatus += new DBprocess.ProgressEventHandler(UpdateProgressBar);  
    dst.BigProcess();
}

void UpdateProgressBar(ProgressEventArgs e)
{
    //At this point, it is possible to check if frmProgr needs
    //InvokeRequired, but if the user needs to call many
    //times the big process, then always use Invoke
    SetValuesCallBack values = new SetValuesCallBack(SetValues);
    this.Invoke(values, new object[] { e });
}

//This delegate is for thread-safe call
delegate void SetValuesCallBack(ProgressEventArgs e);
//Here is the thread-safe work done.
private void SetValues(ProgressEventArgs e)
{
    this.frmProgr.progressBar1.Value = e.Percent;
    this.frmProgr.label1.Text = e.Message + " iterations = " + 
        e.Extradata.ToString("###.00") +"%";
    if (e.Extradata == 100.0) //Is the process finished?
    {
        this.frmProgr.progressBar1.Maximum = 100;
        this.frmProgr.progressBar1.Value = 100;
        this.frmProgr.label1.Text = "Big Process Terminated";
        MessageBox.Show("Work done");
        frmProgr.Close();
    }
}

In this case, we are using a different thread for the long process and using thread-safe calls for updating the progress form.

UI_progress.JPG

Then, you have a pretty simple and safe solution to the problem.

Conclusion

As a result, you have a clean application, with specific layers separation and not only a program with long processes running where the final user does not know if it is blocked or doing something strange and obscure inside the "box".

History

  • 12th December, 2008: Initial post

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer
Mexico Mexico
A humble Linux User

Written By
Software Developer (Senior) La Torre del Vigía, A.R.
Mexico Mexico
Computers Systems Engineer

Comments and Discussions

 
GeneralGood example of threads and delegates Pin
Donsw13-Feb-09 11:17
Donsw13-Feb-09 11:17 
GeneralGood but I prefer Synchronizationcontext Pin
chrono_dev9-Jan-09 2:19
chrono_dev9-Jan-09 2:19 
Have you seen "Synchronizationcontext" ?

Look this link ![] It's a good solution...

According to Eric Vernier (Microsoft),

SynchronizationContext ctx = SynchronizationContext.Current;
    // thanks to anonymous methods
    ThreadPool.QueueUserWorkItem(
        delegate
        {
            for (int i=0;i<60;i++)
            {
              Thread.Sleep(1000);
              ctx.Send(delegate
              {
                  label1.Text = i.ToString();
              },null);
            }
        }
    );


Bye
GeneralSimpler ways Pin
Gonzalo Cao15-Dec-08 21:57
Gonzalo Cao15-Dec-08 21:57 
GeneralMy vote of 2 Pin
gxdata15-Dec-08 17:17
gxdata15-Dec-08 17:17 
GeneralBackgroundWorker Pin
KevinAG15-Dec-08 13:56
KevinAG15-Dec-08 13:56 
RantWell written, but certainly not advanced material Pin
Saar Yahalom12-Dec-08 9:21
Saar Yahalom12-Dec-08 9:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.