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.
public void BigProcess()
{
float x = 0;
float Limit = 150;
for (int i = 0; i <= Limit; i++)
{
x = (i / Limit) * 100;
ProgressStatus(new ProgressEventArgs(Convert.ToInt32(x), i.ToString(), x));
Thread.Sleep(100);
}
}
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.
private void button1_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(DBWork));
frmProgr.ShowDialog();
}
private void DBWork(object o)
{
DBprocess dst = new DBprocess();
dst.ProgressStatus += new DBprocess.ProgressEventHandler(UpdateProgressBar);
dst.BigProcess();
}
void UpdateProgressBar(ProgressEventArgs e)
{
SetValuesCallBack values = new SetValuesCallBack(SetValues);
this.Invoke(values, new object[] { e });
}
delegate void SetValuesCallBack(ProgressEventArgs e);
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)
{
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.
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