C# Progress Bar based on number of lines in file - c#

I would like to perform the following action in C#:
Read the amount of lines in a specific text file.
Depending on the amount of lines in a text file, read each line and update the progress bar.
This is what I have so far:
private void Form1_Load(object sender, System.EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
int lineCount = 0;
int max = 100;
float percent;
using (var reader = File.OpenText(#"C:\file.txt"))
{
toolStripLabel1.Text = "Initializing...";
while (reader.ReadLine() != null)
{
lineCount++;
}
reader.Close();
for (int i = 0; i < lineCount; i++)
{
percent = (max / lineCount);
toolStripLabel1.Text = i.ToString() + " - " + percent + "%";
bw.ReportProgress(Convert.ToInt32(percent));
percent = percent + percent;
// Thread.Sleep(100);
}
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
// progressBar1.Value = (int)(((decimal)currentPosition / (decimal)length) * (decimal)100);
this.Text = e.ProgressPercentage.ToString();
}
Anyone have an idea on how to properly calculate and display the progress bar depending on what line is being read from the file?
Thanks in advance!

There are several problems with your code:
You're first reading the file, then after it has all been read you start updating the progress bar, which doesn't really make any sense.
You're doing integer division in your percentage calculation.
The percentage calculation isn't quite right.
You're updating the ToolStripLabel from the worker thread.
Try this:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
var files = File.ReadAllLines( #"C:\file.txt" );
for( int i = 0; i < files.Length; i++ )
{
var line = files[i];
// do work on the current line here
int percentage = (int)( ( i / (double)files.Length ) * 100.0 );
bw.ReportProgress( percentage );
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
toolStripLabel1.Text = e.ProgressPercentage.ToString() + "%";
this.Text = e.ProgressPercentage.ToString();
}
If the file is very large and it's the actual reading that takes time, you should go back to your original way of reading it, but update the progress for every line instead of after. Though then you're back to the issue of not knowing how many lines there are before you have read the file. In that case - you could estimate the progress based on how many bytes/chars you have read compared to the full size of the file, which you can get without reading it all.

There are a few things you need to do
try this : replace
percent = (max / lineCount);
with this
percent = (100.0 * i / lineCount);
and remove percent = percent + percent;

Try this:
private void InvokeLabel(string text)
{
if (toolStripLabel1.InvokeRequired)
{
toolStripLabel1.Invoke(new Action<string>(InvokeLabel), text);
}
else
{
toolStripLabel1.Text = text;
}
}
For your progress bar it's the same code

Related

C# Background Worker only reports progress after entire processing is complete

I have this issue with my background worker where it only fires after my task is completed and not during. I have made sure to segment the progress properly but its still not firing. I'm not sure what else I can do.
Here is my code:
private int segmentHalf = 0;
private int segmentFull = 0;
public AutoMaticOne()
{
InitializeComponent();
backgroundWorker.WorkerReportsProgress = true;
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var backgroundWorker = sender as BackgroundWorker;
List<PrintObject> pol = new List<PrintObject>();
var program = programsData.Get(programSelectionInput.Text);
var fields = fieldsData.GetAllByTaskId(program.Id);
pol = printerData.Load(Input, program.Name,fields,program.Delimiter);
pol = pol.OrderBy(x => x.FilePath).ToList();
if (pol != null)
{
for(int i =0;i<pol.Count();i++)
{
segmentHalf = (((i + 1) / pol.Count()) * 100) / 2;
segmentFull = segmentHalf * 2;
backgroundWorker.ReportProgress(segmentHalf);
print.Process(pol[i].FilePath, pol[i].PrinterDriver);
infoInput.Invoke((MethodInvoker)delegate {
infoInput.Text = infoInput.Text + "\r\n" + pol[i].FileName + " - " + pol[i].PrinterDriver;
});
backgroundWorker.ReportProgress(segmentFull);
}
}
}
private void backgroundWorker_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
// Change the value of the ProgressBar to the BackgroundWorker progress.
ProgressBar.Value = e.ProgressPercentage;
ProgressBarLabel.Text = e.ProgressPercentage + "%";
}
private void backgroundWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
InputDirectory.Enabled = true;
OutputDirectory.Enabled = true;
InputDirectoryButton.Enabled = true;
OutputDirectoryButton.Enabled = true;
MessageBox.Show("Task has been Completed, Output files can be found at " + OutputDirectory.Text, "Task Completed");
Start.Enabled = true;
}
When I start with 10 files, it seems fine. But when it loads something like 1000, then it only reports the progress at the end.
SegmentHalf and Full are declared above the constructor
As long as i < pol.Count - 1, (i + 1) / pol.Count will be 0. Integer division truncates towards 0. Your code will execute 0 * 100 for all except the last file.
You can fix it like this:
//segmentHalf = (((i + 1) / pol.Count()) * 100) / 2;
segmentHalf = (((i + 1) * 100) / pol.Count) / 2;

How can i check if all the files were downloaded?

Before i tried to check if progressBar2 that show overall download progress is at 100% but it's not really working. Is there another way more sure way to check it ?
private void btnDownload_Click(object sender, EventArgs e)
{
//urll.Add("http://download.thinkbroadband.com/1GB.zip");
btnDownload.Enabled = false;
label7.Text = "Downloading...";
getTotalBytes(countryList);
CreateCountryDateTimeDirectories(newList);
downloadFile(newList);
}
private Queue<string> _downloadUrls = new Queue<string>();
private async void downloadFile(IEnumerable<string> urls)
{
foreach (var url in urls)
{
_downloadUrls.Enqueue(url);
}
await DownloadFile();
}
private async Task DownloadFile()
{
if (_downloadUrls.Any())
{
WebClient client = new WebClient();
client.DownloadProgressChanged += ProgressChanged;
client.DownloadFileCompleted += Completed;
var url = _downloadUrls.Dequeue();
sw = Stopwatch.StartNew();
if (url.Contains("true"))
{
await client.DownloadFileTaskAsync(new Uri(url), countriesMainPath + "\\" + currentDownloadCountry + "\\" + count + "Infrared.jpg");
}
else
{
await client.DownloadFileTaskAsync(new Uri(url), countriesMainPath + "\\" + currentDownloadCountry + "\\" + count + "Invisible.jpg");
}
return;
}
}
double percentageTotalDownload = 0;
double totalBytesDownloaded = 0;
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// Calculate download speed and output it to labelSpeed.
label3.Text = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00"));
// Update the progressbar percentage only when the value is not the same.
double bytesInCurrentDownload = (double)e.BytesReceived;
double totalBytesCurrentDownload = double.Parse(e.TotalBytesToReceive.ToString());
double percentageCurrentDownload = bytesInCurrentDownload / totalBytesCurrentDownload * 100;
ProgressBar1.Value = int.Parse(Math.Truncate(percentageCurrentDownload).ToString());//e.ProgressPercentage;
// Show the percentage on our label.
Label4.Text = e.ProgressPercentage.ToString() + "%";
// Update the label with how much data have been downloaded so far and the total size of the file we are currently downloading
label10.Text = string.Format("{0} MB's / {1} MB's",
(e.BytesReceived / 1024d / 1024d).ToString("0.00"),
(e.TotalBytesToReceive / 1024d / 1024d).ToString("0.00"));
//Let's update ProgressBar2
totalBytesDownloaded = e.BytesReceived + bytesFromCompletedFiles;
percentageTotalDownload = totalBytesDownloaded / totalBytesToDownload * 100;
progressBar2.Value = (int)percentageTotalDownload;
label6.Text = progressBar2.Value.ToString() + "%";
}
long bytesFromCompletedFiles = 0;
// The event that will trigger when the WebClient is completed
private async void Completed(object sender, AsyncCompletedEventArgs e)
{
await DownloadFile();
}
For example if i have 100 urls and it's start downloading then i want to know in the completed event when all the files downloaded and not only one each time.
You can keep track of how many downloads have been completed in an counter variable. Because of the multiple threads that can access that counter, use the Interlocked class to manipulate that counter.
This are the changes needed in your code:
private int urlCount = 0; // keep track of how many urls are processed
private async void downloadFile(IEnumerable<string> urls)
{
urlCount = 0;
foreach (var url in urls)
{
_downloadUrls.Enqueue(url);
urlCount++;
}
// urlCount is now set
await DownloadFile();
}
And here is the handling of the counter and the check if we are done
private async void Completed(object sender, AsyncCompletedEventArgs e)
{
// urlCount will be decremented
// cnt will get its value
var cnt = System.Threading.Interlocked.Decrement(ref urlCount);
if (cnt > 0) {
await DownloadFile();
}
else
{
// call here what ever you want to happen when everything is
// downloaded
"Done".Dump();
}
}
I haven't understood it very well, but what you are trying to accomplish is that your progress bar is showing progress of download all files and not one file then reset then another file that reset.
If that is the case, then why you do not try foreach file get size and sum it to totalBytesToDownload and then use it in progress bar
So
foreach(string url in urll)
{
//get url file size
totalBytesToDownload = totalBytesToDownload + urlSizeYouGot;
}

Calculate time of processing a rule and use in progress-bar

I have created a program that uploads a file in server using ftp. Now I want to use a progress bar when file uploading in server. Means when file is upload progress bar start with value=0 when upload doing his work value of progress bar increase and when upload done value be max and then return to default;
i have no problem with upload just i dont know how to use progress bar when i uploading a file in server.
please help me.
my program picture
private void button1_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
backgroundWorker1.RunWorkerAsync();
Upload(#openFileDialog1.FileName);
}
else
{ }
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 100; i++)
{
Thread.Sleep(2);
backgroundWorker1.ReportProgress(i);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
this.Text = e.ProgressPercentage.ToString();
}
Here is an example of a program I use that processes a dynamic amount of parts and reports the progress. Hope it helps!
Here is the end of my part processing method:
int Progress = Convert.ToInt16(((Convert.ToDecimal(intCounter) / Convert.ToDecimal(txtPartsList.Lines.Count()))) * 100);
bw.ReportProgress(intCounter);
and the code for my progress changed handle:
private void bwExecuteProcess_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
int Progress = Convert.ToInt16(Math.Floor(((Convert.ToDecimal(e.ProgressPercentage) / Convert.ToDecimal(txtPartsList.Lines.Count()))) * 100));
lblTotal.Text = string.Format("Total Processed: {0} of {1}", e.ProgressPercentage, txtPartsList.Lines.Count());
lblReaderTime.Text = string.Format("Time Elapsed (sec): {0}", (swMainProcess.ElapsedMilliseconds / 1000));
pgsMain.Value = Progress;
lblPercentComplete.Text = string.Format("Percent Complete: {0}%", Progress);
ttpMain.SetToolTip(pgsMain, string.Format("{0}% Complete", Progress));
}

I'm trying to use backgroundworker but it doesn't work - why?

This is the code of the DoWork event the ProgressChanged event and the RunWorkerCompleted event. The problem is that the progressBar is getting to 100% much faster before the function process operation is end. So when the progressBar is up to 100% I'm getting error exception since the progressBar can't be 101%
I need somehow to make that the progressBar will get progress according to the function process / progress. I guess that something is wrong with my calculation in the DoWork event.
In the Form1 top I added:
Int i;
In the constructor I did:
i = 0;
backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.RunWorkerAsync();
And this is the events of the Backgroundworker:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
//int currentLength;
//int currentIndex;
//int lastIndex = 0;
string startTag = "T256=\"";
string endTag = "\"";
int startTagWidth = startTag.Length;
//int endTagWidth = endTag.Length;
int index = 0;
h = new StreamReader(#"d:\DeponiaSplit\testingdeponias_Translated.txt");
while ((line = h.ReadLine()) != null)
{
if (index > f.LastIndexOf(startTag))
{
break;
}
int startTagIndex = f.IndexOf(startTag, index);
int stringIndex = startTagIndex + startTagWidth;
index = stringIndex;
int endTagIndex = f.IndexOf(endTag, index);
int stringLength = endTagIndex - stringIndex;
if (stringLength != 0)
{
string test = f.Substring(stringIndex, stringLength);
f = f.Substring(0, stringIndex) + line + f.Substring(stringIndex + stringLength);
if (listBox1.InvokeRequired)
{
textBox1.Invoke(new MethodInvoker(delegate { textBox1.Text = line; }));
}
i = i + 1;
System.Threading.Thread.Sleep(500);
worker.ReportProgress((i * 1));
}
}
h.Close();
StreamWriter w = new StreamWriter(#"D:\New folder (24)\000004aa.xml");
w.AutoFlush = true;
w.Write(f);
w.Close();
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//this.progressBar1.Text = (e.ProgressPercentage.ToString() + "%");
progressBar1.Value = e.ProgressPercentage;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((e.Cancelled == true))
{
this.progressBar1.Text = "Canceled!";
}
else if (!(e.Error == null))
{
this.progressBar1.Text = ("Error: " + e.Error.Message);
}
else
{
this.progressBar1.Text = "Done!";
}
}
Why doesn't it work correctly?
Working using FileStream
Now I wanted to add to the progressBar a label which will show % and the label will move according to the progressBar I don't want to disable the progressBar green color progress just to add % and show the numbers in percentages.
So in the ProgressChanged event I did :
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
label3.Text = (e.ProgressPercentage.ToString() + "%");
}
But it doesn't work - the label13 doesn't move only the % changed to 1. I want to see something like 1%...2%...3%... and so on. How can I do it?
Why don't you use File.ReadAllLines, it returns an array of strings. You could report your progress as the percentage of the line you are processing to the total number of lines:
string[] lines = File.ReadAllLines(#"d:\DeponiaSplit\testingdeponias_Translated.txt");
// ...
worker.ReportProgress(i * 100 / lines.Length);
The "ReportProgress()" method is reporting "i" right after "i" has been incremented with the "i+1" statment. i is a variable that is incremented every time you have found a string that has matched your provided parameters. I think the problem here is that you are reporting an integer without context. Do you know how many lines total in the file contain a string that matches your parameters. I would suggest reporting (i/totalNumLinesMatchingParameters) * 100. This would report a number in terms of percentage. However, this does not include the action of writing the File. So you may want to scale the above differently if you intend to include the action of writing the File in your progress bar/progress bar label...

Update the Progress bar using winforms c#

There is a functionality in my module, where the user can
scan the number of serial ports in the system and when the
user clicks "Auto scan" button, the code will have to go
through each serial port and send a test message and wait
for the reply.
I am using Progress bar control to show process of autoscan.
For which i need to pass the value to "x" and "Y" in my code to
update the bar. How can i pass the value since my code is already
in a foreach loop for getting the serialports.
Y = should pass the value of total number of serial ports
X = should iterate through each port and pass the value
Hope i am clear with req.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
string strAckData = "";
foreach (SerialPort sp in comPortsList)
{
sp.Open();
string sendData = "Auto scan";
sp.Write(sendData);
strAckData += "Connection live on port " + sp.ReadExisting() + "\n";
sp.Close();
double dIndex = (double)x; **//How to pass the value here ?**
double dTotal = (double)y; **//How to pass the value here ?**
double dProgressPercentage = (dIndex / dTotal);
int iProgressPercentage = (int)(dProgressPercentage * 100);
// update the progress bar
backgroundWorker1.ReportProgress(iProgressPercentage);
}
richTextBox1.Invoke(new MethodInvoker(delegate { richTextBox1.Text = strAckData; }));
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ProgressBar.Value = e.ProgressPercentage;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
StatusLabel.Text = "Auto Scan completed";
}
You can get the number of ports from your comPortsList variable. Then the index is just a matter of incrementing a loop variable:
double dTotal = (double)(comPortsList.Count);
double dIndex = 0;
foreach (SerialPort sp in comPortsList)
{
// talk to serial port as at the moment
dIndex = dIndex + 1; // or ++dIndex to be more concise
double dProgressPercentage = dIndex / dTotal;
// etc.
}

Categories