UX is most important in any application and responsive application is an add-on to make UI free by running long running task in background. Sometimes we need to show more useful information about long running task to keep user informed about progress. In this article, we will be looking into showing up progress status for long running process with Task Parallel Library (TPL).
The above class looks pretty simple without any kind of noise in it. In case of percentage there is no multiplication of 100 by we will be using ToString("p") to show up percentage value.
After completion of progress class, we need to populate classes member according to need on processing function for image re-sizing. If you look into below function, ImageResizeProgress class is wrapped into IProgress interface under parameter. After changing values of curProgress object, whenever showing status is required we just need to call progress.Report(curProgress), in which it will trigger function that we are going to create next.
Let's create function which will display status on console. This static method will only take ImageResizeProgress as a argument. You can consume object to show status in your own way.
Now, everything is setup we just need to call ProcessFilesForImageDimension function to initiate operation. For IProgress interface we need to pass concrete class implementation which again is defined under mscorlib http://msdn.microsoft.com/en-us/library/hh194158(v=vs.110).aspx. The Progress class constructor takes action as parameter. In our case we have defined method named ShowStatus to pass in constructor.
Now, everything is set we can expect result something like this.
Source code: https://www.dropbox.com/s/tf9vughitrj426s/AsyncProgessbar.zip
In this particular example, we will be creating a Console application to re-size any amount of jpg files under directory with new image dimension but our main focus would be on showing progress status.
Prior to .Net 4.5 Framework version, there was no inbuilt mechanism to show status of task. If it was needed, then we need to create event handler on class that is processing the long running task with custom defined event argument for progress status class and then subscription need to be done on consuming class for getting progress information. This was better and tidy approach for getting progress status but lot of things were needed to make it work.
In 4.5, an interface named IProgress<T> is introduced having just single function Report<T value>. Due to generic by nature we could use custom defined classes or any on other built in types to show status. It is included in mscorlib.dll. http://msdn.microsoft.com/en-us/library/hh138298(v=vs.110).aspx
Let's roll and explore on the new approach.
We will be having our own custom class to show status of total files, skipped, processed and percentage of completion.
public class ImageResizeProgress
{
public int TotalFiles { get; set; }
public int SkippedFiles { get; set; }
public int ProcessedFiles { get; set; }
public decimal Percentage
{
get
{
if ((TotalFiles - SkippedFiles) != 0)
{
return ProcessedFiles / (decimal)(TotalFiles - SkippedFiles);
}
return 1;
}
}
}
The above class looks pretty simple without any kind of noise in it. In case of percentage there is no multiplication of 100 by we will be using ToString("p") to show up percentage value.
After completion of progress class, we need to populate classes member according to need on processing function for image re-sizing. If you look into below function, ImageResizeProgress class is wrapped into IProgress interface under parameter. After changing values of curProgress object, whenever showing status is required we just need to call progress.Report(curProgress), in which it will trigger function that we are going to create next.
public Task ProcessFilesForImageDimension(string fileOrDirectory,
IProgress<ImageResizeProgress> progress)
{
var curProgress = new ImageResizeProgress();
// Delegate to resize image
Action<string> resize = (file) =>
{
Thread.Sleep(100);
if (ResizeImage(file))
{
curProgress.ProcessedFiles++;
}
else
{
curProgress.SkippedFiles++;
}
progress.Report(curProgress);
};
return Task.Factory.StartNew(() =>
{
if (Directory.Exists(fileOrDirectory))
{
var files = Directory.GetFiles(fileOrDirectory, "*.jpg");
curProgress.TotalFiles = files.Length;
progress.Report(curProgress);
foreach (var file in files)
{
resize(file);
}
}
else if (File.Exists(fileOrDirectory))
{
resize(fileOrDirectory);
}
else
{
progress.Report(curProgress);
}
});
}
Let's create function which will display status on console. This static method will only take ImageResizeProgress as a argument. You can consume object to show status in your own way.
private static void ShowStatus(ImageResizeProgress progress)
{
Console.Clear();
Console.SetCursorPosition(0, 0);
Console.WriteLine("Completion percentage: " + progress.Percentage.ToString("p"));
Console.WriteLine("Total Files: " + progress.TotalFiles);
Console.WriteLine("Processed Files: " + progress.ProcessedFiles);
Console.WriteLine("Skipped Files: " + progress.SkippedFiles);
}
Now, everything is setup we just need to call ProcessFilesForImageDimension function to initiate operation. For IProgress interface we need to pass concrete class implementation which again is defined under mscorlib http://msdn.microsoft.com/en-us/library/hh194158(v=vs.110).aspx. The Progress class constructor takes action as parameter. In our case we have defined method named ShowStatus to pass in constructor.
private static void Main(string[] args)
{
ImageDimensionManager dimensionManager = new ImageDimensionManager();
// TODO: Change location
Task tskImageResize = dimensionManager.ProcessFilesForImageDimension
(@"C:\Users\Public\Pictures\Sample Pictures",
new Progress<ImageResizeProgress>(ShowStatus));
tskImageResize.Wait();
}
Now, everything is set we can expect result something like this.
Source code: https://www.dropbox.com/s/tf9vughitrj426s/AsyncProgessbar.zip
Comments
Post a Comment