Board logo

subject: Responsive UI With Time Taking Tasks [print this page]


Responsive UI With Time Taking Tasks
Responsive UI With Time Taking Tasks

Thread t = new Thread (new Thread Start (TimeConsumingFunction));

t.Start();

Timer1.Start();

}

//Timer1 had a tick even associated Timer1_Tick

Timer1_Tick()

{

// Code to increment progress bar goes here..

}

But this dint work.

I tried to search on net but could'nt get any thing relevant as my problem was quite specific and unique.

I spent quite some time in going through some articles on Threading etc.

Finally I found 2 ways to achieve this and decided to put it here.......

1st Way

BackgroundWorker Component

When you want a responsive UI and you are faced with long delays associated with some time consuming operations, the BackgroundWorker component provides a convenient solution.

The BackgroundWorker is available in Tool Box and you can drag it on your form.

Now the BackgroundWorker class exposes few events. The ones that I used are...

DoWork

ProgressChanged

RunWorkerCompleted 1. DoWork

This gets invoked when you start the Worker (Thread). To start the worker you need to call the method RunWorkerAsync

Calling this function will invoke the DoWork event.

Your time consuming work needs to be done in the DoWork event.

The signature of this event is

DoWork(sender object, DoWorkEventArgs e)

Some important properties of DoWorkEventArgs

Argument - To pass an argument from RunWorkerAsync to DoWork event

Cancel - To state if the job is cancelled

Result - To store the result and make in available to other events.

We will see each with example.

Argument

Any arguments that you need to pass, can be passed through function RunWorkerAsync.

RunWorderAsync(101) // 101 is the argument I am passing.

The e.Argument will get this value

The event DoWork would be something like this....

Private void Backgroundworker1_DoWork(object sender, DoWorkEventArgs e)

{

ComputeFact((int)e.Argument) //This is similar to ComputeFact(101)

}

Cancel

There might be a requirement to cancel the timeconsuming task in middle.

For this you have to call a method CancelAsync()

When this method is called CancellationPending property of sender object is set to true.

This can be checked in DoWork event and e.Cancel should be set to true.

The same object 'e' of DoWorkEventArgs get carried to other events like RunWorkerCompleted and ProgressChanged and can be utilized there.

Result

This property can be used to store result in DoWork event.

This Result gets propagated to other events through the same object 'e'.

Summary of DoWork:- This event is raised when you call the RunWorkerAsync method. This is where you start the operation that performs the potentially time-consuming work.

Your code in the DoWork event handler should periodically check the CancellationPending property value and abort the operation if it is true. (By setting e.Cancel to true where e is object of type DoWorkEventArgs)

The result value should be stored in e.Result where e is object of type DoWorkEventArgs.

2. ProgressChanged.

This event is called each time the object sender calls the function ReportProgress

The reportProgress method accepts an integer argument which should be the percentage of progress made.

For using this the BackGroundWorker's ReportsProgress property should be set to true.

The Signature for this event is

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)

e.ProgressPercentage - Will have the percentage reported by ReportProgress method

3. RunWorkerCompleted

This event gets fired when the Worker Thread gets completed i.e when the Thread finishes to execute the code in DoWork event.

The signature for this event is

private void backgroundWorker1_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)

e.Cancelled will have the Boolean value as true if e.Cancel is set true in DoWork event.

e.Result will contain the result.

e.Error will have the error no in case of any

As an example where the time consuming event is to compute a factorial is below:-

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Threading;

namespace BackgroundWorkerPrj

{

public partial class Form1 : Form

{

long result = 1;

int percentprog, oldpercentprog;

public Form1()

{

InitializeComponent();

}

int orignalnum;

private void Form1_Load(object sender, EventArgs e)

{

InitializeBackgroundWorker();

orignalnum = 50;

backgroundWorker1.RunWorkerAsync((int)orignalnum);

}

private void InitializeBackgroundWorker()

{

backgroundWorker1.DoWork+=new DoWorkEventHandler(backgroundWorker1_DoWork);

backgroundWorker1.ProgressChanged+=new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);

backgroundWorker1.RunWorkerCompleted+=new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);

backgroundWorker1.WorkerReportsProgress = true;

}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)

{

BackgroundWorker w = sender as BackgroundWorker;

e.Result=computeFactorial((int)e.Argument,w,e);

}

private long computeFactorial(int s,BackgroundWorker w,DoWorkEventArgs e)

{

Thread.Sleep(100);

if (w.CancellationPending)

e.Cancel = true;

else

{

//To caluclate the progress percentage.

percentprog = ((orignalnum - s) * 100) / orignalnum;

//If there is any progress than last iteration...

if (percentprog > oldpercentprog)

{

oldpercentprog = percentprog;

w.ReportProgress(percentprog);

}

if (s == 1)

result= 1;

else

result = result * s*computeFactorial(s - 1, w, e);

}

return result;

}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)

{

this.progressBar1.Value = e.ProgressPercentage;

}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

{

if (e.Error == null)

{

if (e.Cancelled == true)

{

label1.Text = "Cancelled";

}

else

{

label1.Text = e.Result.ToString();

}

}

else

label1.Text = "Error Occured";

}

}

}

Limitation :-

This component does not exist in .Net 1.1. So the 2nd way would work there.

2nd Way

Creating Threads.

This is a simple way of creating threads. Just that the time consuming operation should be made a background thread by using the attribute IsBackground = true.

So the code would look like this

{

Thread t = new Thread (new Thread Start (TimeConsumingFunction));

t.IsBackGround=true;

t.Start();

Timer1.Start();

}

//Timer1 had a tick even associated Timer1_Tick

Timer1_Tick()

{

// Code to increment progress bar goes here..

Thread.Sleep(100);

}

Deepa Lakhani

deepalakhani@yahoo.com




welcome to loan (http://www.yloan.com/) Powered by Discuz! 5.5.0