Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Wednesday, February 17, 2016 6:44 PM
Hello dear members !
I have a small issue with a backgroundworker and the ReportProgress method.
I have a class that encrypts a file with rijndael algorithm.
now i want to update the progress to a progressbar while doing this (if files ar large it takes more time)
using (FileStream fsIn = new FileStream(inputFile, FileMode.Open))
{
int data;
while ((data = fsIn.ReadByte()) != -1)
{
cs.WriteByte((byte)data);
//backgroundWorker.ReportProgress(FileProgress)
}
}
Where "FileProgress" would be the amount to pass through the progressbar.Value.
In my DoWork i call the method that encrypts :
private void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
if (MessageBox.Show("File is ready , Click YES to start Encrypting ", "", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
{
if (radioButtonRijndael.Checked)
{
Rijndael_FileEncrypt rijnFile = new Rijndael_FileEncrypt();
rijnFile.EncryptFile(inputfile, outputfile, pass, Key); // This Calls the encrypt method from my class shown above
}
else if (radioButtonAES.Checked)
{
Aes_FileEncrypt aes = new Aes_FileEncrypt();
aes.EncryptFile(inputfile, outputfile, pass, Key);
}
}
Lets say the file is 500 000 000bytes (500mb),
and i would want to pass the progress in a way that it converts it to Percentage ,so that the actual process of Writing bytes is running equally with the progress showed on the progressBar.
Do i pass a backgroundWorker in my method and put it in the while loop?
What would be the proper way of doing this ?
Thank you !
Kind regards
All replies (13)
Wednesday, February 17, 2016 7:27 PM ✅Answered
Hi again,
There's a complete example and explanation here:
https://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
But basically, you raise the reportprogress event like you have there
while ((data = fsIn.ReadByte()) != -1)
{
cs.WriteByte((byte)data);
backgroundWorker.ReportProgress(Some number goes here)
}
And you subscribe to the event :
backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged)
That handler gets the number you give it when you raise the event and you use that to set your value in the ProgressBar rather than the text like it does there.
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
Hope that helps.
Technet articles: WPF: Layout Lab; All my Technet Articles
Wednesday, February 17, 2016 7:27 PM
Hello dear members !
I have a small issue with a backgroundworker and the ReportProgress method.
I have a class that encrypts a file with rijndael algorithm.
now i want to update the progress to a progressbar while doing this (if files ar large it takes more time)
You can only do progress reproting between distinct lines of code. About 95% of all classes doing file work do not provide any way to get progress reports on any given file (Y/X bytes processed).
So usually you end up having to disect the class/function you are using down to the loop it is using, doing the looping yourself and report between that. Or just realise that it is not worth the effort.
Also doing GUi updates too often can overload the GUI thread with redraw events. But usually a progress bar is rather save here (compared to a textbox or label you keep appending too).
Only do writing to the GUI from the ProgressReported or RunWorkerCompleted Events. Multithreading and GUI's have some issues. And those two events are automagically Invoked on the GUI thread, taking that headache from you.
Here is some example code on how to use the BackgroundWorker to get all Primes within a number range:
#region Primenumbers
private void btnPrimStart_Click(object sender, EventArgs e)
{
if (!bgwPrim.IsBusy)
{
//Prepare ProgressBar and Textbox
int temp = (int)nudPrim.Value;
pgbPrim.Maximum = temp;
tbPrim.Text = "";
//Start processing
bgwPrim.RunWorkerAsync(temp);
}
}
private void btnPrimCancel_Click(object sender, EventArgs e)
{
if (bgwPrim.IsBusy)
{
bgwPrim.CancelAsync();
}
}
private void bgwPrim_DoWork(object sender, DoWorkEventArgs e)
{
int highestToCheck = (int)e.Argument;
//Get a reference to the BackgroundWorker running this code
//for Progress Updates and Cancelation checking
BackgroundWorker thisWorker = (BackgroundWorker)sender;
//Create the list that stores the results and is returned by DoWork
List<int> Primes = new List<int>();
//Check all uneven numbers between 1 and whatever the user choose as upper limit
for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2)
{
//Report progress
thisWorker.ReportProgress(PrimeCandidate);
bool isNoPrime = false;
//Check if the Cancelation was requested during the last loop
if (thisWorker.CancellationPending)
{
//Tell the Backgroundworker you are canceling and exit the for-loop
e.Cancel = true;
break;
}
//Determin if this is a Prime Number
for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2)
{
if (PrimeCandidate % j == 0)
isNoPrime = true;
}
if (!isNoPrime)
Primes.Add(PrimeCandidate);
}
//Tell the progress bar you are finished
thisWorker.ReportProgress(highestToCheck);
//Save Return Value
e.Result = Primes.ToArray();
}
private void bgwPrim_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pgbPrim.Value = e.ProgressPercentage;
}
private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
pgbPrim.Value = pgbPrim.Maximum;
this.Refresh();
if (!e.Cancelled && e.Error == null)
{
//Show the Result
int[] Primes = (int[])e.Result;
StringBuilder sbOutput = new StringBuilder();
foreach (int Prim in Primes)
{
sbOutput.Append(Prim.ToString() + Environment.NewLine);
}
tbPrim.Text = sbOutput.ToString();
}
else
{
tbPrim.Text = "Operation canceled by user or Exception";
}
}
#endregion
Wednesday, February 17, 2016 8:20 PM
Hi again,
There's a complete example and explanation here:
But basically, you raise the reportprogress event like you have there
while ((data = fsIn.ReadByte()) != -1) { cs.WriteByte((byte)data); backgroundWorker.ReportProgress(Some number goes here) }
And you subscribe to the event :
backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged)
That handler gets the number you give it when you raise the event and you use that to set your value in the ProgressBar rather than the text like it does there.
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar1.Value = e.ProgressPercentage; }
Hope that helps.
Hello again sir and thank you for your time !
I have learned using the backgroundWorker with that article ,
Im quite confused on were to put what (not a pro with events),
I put the event
backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged)
**after **
backgroundWorker.RunWorkerAsync();
but when encrypting ,my UI freezes , i think because of the number i put in the reportProgress().
while ((data = fsIn.ReadByte()) != -1)
{
cs.WriteByte((byte)data);
backgroundWorker.ReportProgress(Convert.ToInt32(fileStrm.Position))
}
Im putting in the fileStream.Position ,i can't figure out how to get the **FileSize bytes **(example) 0-50000 to run equally to 0-100 (value of progressBar) ...
Or its because im doing something else wrong...
Sorry that im not understanding all your explanations ...
Wednesday, February 17, 2016 8:26 PM
You can only do progress reproting between distinct lines of code. About 95% of all classes doing file work do not provide any way to get progress reports on any given file (Y/X bytes processed).
So usually you end up having to disect the class/function you are using down to the loop it is using, doing the looping yourself and report between that. Or just realise that it is not worth the effort.
Also doing GUi updates too often can overload the GUI thread with redraw events. But usually a progress bar is rather save here (compared to a textbox or label you keep appending too).Only do writing to the GUI from the ProgressReported or RunWorkerCompleted Events. Multithreading and GUI's have some issues. And those two events are automagically Invoked on the GUI thread taking that headache from you.
Here is some example code on how to use the BackgroundWorker to get all Primes within a number range:
#region Primenumbers private void btnPrimStart_Click(object sender, EventArgs e) { if (!bgwPrim.IsBusy) { //Prepare ProgressBar and Textbox int temp = (int)nudPrim.Value; pgbPrim.Maximum = temp; tbPrim.Text = ""; //Start processing bgwPrim.RunWorkerAsync(temp); } } private void btnPrimCancel_Click(object sender, EventArgs e) { if (bgwPrim.IsBusy) { bgwPrim.CancelAsync(); } } private void bgwPrim_DoWork(object sender, DoWorkEventArgs e) { int highestToCheck = (int)e.Argument; //Get a reference to the BackgroundWorker running this code //for Progress Updates and Cancelation checking BackgroundWorker thisWorker = (BackgroundWorker)sender; //Create the list that stores the results and is returned by DoWork List<int> Primes = new List<int>(); //Check all uneven numbers between 1 and whatever the user choose as upper limit for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2) { //Report progress thisWorker.ReportProgress(PrimeCandidate); bool isNoPrime = false; //Check if the Cancelation was requested during the last loop if (thisWorker.CancellationPending) { //Tell the Backgroundworker you are canceling and exit the for-loop e.Cancel = true; break; } //Determin if this is a Prime Number for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2) { if (PrimeCandidate % j == 0) isNoPrime = true; } if (!isNoPrime) Primes.Add(PrimeCandidate); } //Tell the progress bar you are finished thisWorker.ReportProgress(highestToCheck); //Save Return Value e.Result = Primes.ToArray(); } private void bgwPrim_ProgressChanged(object sender, ProgressChangedEventArgs e) { pgbPrim.Value = e.ProgressPercentage; } private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { pgbPrim.Value = pgbPrim.Maximum; this.Refresh(); if (!e.Cancelled && e.Error == null) { //Show the Result int[] Primes = (int[])e.Result; StringBuilder sbOutput = new StringBuilder(); foreach (int Prim in Primes) { sbOutput.Append(Prim.ToString() + Environment.NewLine); } tbPrim.Text = sbOutput.ToString(); } else { tbPrim.Text = "Operation canceled by user or Exception"; } } #endregion
Hello sir and thank you for your reply !
I understand on how to use the BackgroundWorker but i can't get the logic for
getting the amount of bytes that is written to run equally with the progressBar,
lets say the file size is 50000bytes ,in my while loop how can i get the report progress to be like this:
byte writing from 0 to 50000 is equal as progress from 0 to 100 ?
Thank you !
Thursday, February 18, 2016 6:55 AM
Hi Csharp_syntra,
If you want to show the progress of the current encryption, you should use the BackgroundWorker.ReportProgress Method (Int32) to report it in the “backgroundWorker_DoWork”.
According to the following similar thread says, you could change the algorithm of encryption and first spit the file into fixed size blocks and then use a loop to encrypt each block and report progress as TotalBlocksEncrypted/TotalBlocks if you just want to encrypt the file only once in your situation.
Best Regards,
Albert Zhang
We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
Click HERE to participate the survey.
Thursday, February 18, 2016 11:53 AM
I understand on how to use the BackgroundWorker but i can't get the logic for
getting the amount of bytes that is written to run equally with the progressBar,
lets say the file size is 50000bytes ,in my while loop how can i get the report progress to be like this:
byte writing from 0 to 50000 is equal as progress from 0 to 100 ?
Thank you !
1. You can report progress before and after the following line:
rijnFile.EncryptFile(inputfile, outputfile, pass, Key); // This Calls the encrypt method from my class shown above
And that is all the progress reporting you will get to do with the code you gave us!
If you want to give progress on how many bytes of the file have been processed you have to:
Stop using EncryptFile
Replicate the entire code of EncryptFile - down the loop that goes over the inputfile - in your BackgroundWorkers DoWork method.
Report progress once per loop, as I did in my example.
Do all the work of reading, encrypting and writing yourself in DoWork.
Even among classes that download stuff via network giving reports on how many bytes have been downloaded is a rare thing.
That is why I said: Most people just realise it is not worth the effort.
2. About the progress bar:
Just set pgb.Maximum to the file lenght. And update currentvalue with pbg.Value with the bytecount your process just passed. It will deal with filling an apropirate amount of the bar.
3. Displaying the progress as a percentile value:
This is a totally different question again. And it is simple mathemathics at that. You got a clear definition of 100% (the inputfile lenght). And a clear definition of how many bytes have been procesed. Turn both values into floats, doubles or decimals and do:
BytesProcessed/FileLenght*100, rounded to a meaningfull value
But again, GUI updates can be quite costly. Updating a label with the new percentage as often as you update the ProgressBar will propably be an issue.
And you need to get 1+2 working before you can even think about this.
Thursday, February 18, 2016 8:20 PM
Regarding part 1, I just read up on how that Encryption works. If I understand it right (I am not 100% sure) it segments the plaintext into "blocks" of variable size (128 bits is most often used). Then it encrypts each block of data independently.
If that is true it would be feasible to read the input file 128 bit/16 byte at a time. Feed it to a prewritten encryption function like this one. Store it to the target file. Then report progress.
You need to know what to do if the remainder of the file is less then a full block (padding it, but with what?)
But again, that all implies that the blocks do not interact with one another after being encrypted.
Friday, February 19, 2016 4:26 PM
I understand on how to use the BackgroundWorker but i can't get the logic for
getting the amount of bytes that is written to run equally with the progressBar,
lets say the file size is 50000bytes ,in my while loop how can i get the report progress to be like this:
byte writing from 0 to 50000 is equal as progress from 0 to 100 ?
Thank you !
1. You can report progress before and after the following line:
rijnFile.EncryptFile(inputfile, outputfile, pass, Key); // This Calls the encrypt method from my class shown above
And that is all the progress reporting you will get to do with the code you gave us!
If you want to give progress on how many bytes of the file have been processed you have to:
Stop using EncryptFile
Replicate the entire code of EncryptFile - down the loop that goes over the inputfile - in your BackgroundWorkers DoWork method.
Report progress once per loop, as I did in my example.
Do all the work of reading, encrypting and writing yourself in DoWork.Even among classes that download stuff via network giving reports on how many bytes have been downloaded is a rare thing.
That is why I said: Most people just realise it is not worth the effort.2. About the progress bar:
Just set pgb.Maximum to the file lenght. And update currentvalue with pbg.Value with the bytecount your process just passed. It will deal with filling an apropirate amount of the bar.3. Displaying the progress as a percentile value:
This is a totally different question again. And it is simple mathemathics at that. You got a clear definition of 100% (the inputfile lenght). And a clear definition of how many bytes have been procesed. Turn both values into floats, doubles or decimals and do:
BytesProcessed/FileLenght*100, rounded to a meaningfull valueBut again, GUI updates can be quite costly. Updating a label with the new percentage as often as you update the ProgressBar will propably be an issue.
And you need to get 1+2 working before you can even think about this.
I tryed 1 & 2 but it doesn't update progress and my UI freezes.
My DoWork method contains this :
try
{
RijndaelManaged RM = new RijndaelManaged();
UnicodeEncoding UE = new UnicodeEncoding();
string VI = VIkey; // max length 8 !
string CustPass = pass; // max length 16 !
byte[] VIK = UE.GetBytes(VI);
byte[] key = UE.GetBytes(CustPass);
RM.Key = key;
RM.IV = VIK;
ICryptoTransform encryptor = RM.CreateEncryptor(RM.Key, RM.IV);
string cryptFile = outputFile;
using (FileStream fsOut = new FileStream(cryptFile, FileMode.Create))
{
using (CryptoStream cs = new CryptoStream(fsOut, RM.CreateEncryptor(RM.Key, RM.IV),
CryptoStreamMode.Write))
{
using (FileStream fsIn = new FileStream(inputFile, FileMode.Open))
{
long l = fsIn.Length;
int a = Convert.ToInt32(l);
int data;
while ((data = fsIn.ReadByte()) != -1)
{
cs.WriteByte((byte)data);
b.ReportProgress(Convert.ToInt32(fsIn.Position / a)*100);
}
};
}
}
}
catch(Exeption ex)
{
MessageBox.Show("Failed to Encrypt File !"+ ex.ToString());
}
I tryed with a simple loop like your example and that works but when reading files byte it doesnt...
Thank you so far for your time and information !
Friday, February 19, 2016 4:29 PM
Regarding part 1, I just read up on how that encryption works If I understand it right (I am not 100% sure) it segments the plaintext into "blocks" of variable size (128 bits is most often used). Then it encrypts each block of data independently.
If that is true it would be feasible to read the input file 128 bit/16 byte at a time. Feed it to a prewritten encryption function like this one Store it to the target file. Then report progress.
You need to know what to do if the remainder of the file is less then a full block (padding it, but with what?)
But again, that all implies that the blocks do not interact with one another after being encrypted.
I guess if there is no other way i will have to split it up into multiple parts but still when encrypting a small txt file for example it should work if the size is the issue here...
Kind regards
Friday, February 19, 2016 7:11 PM
The approach I usually use is to make a progress indicator indeterminate.
With that you don't need any fancy stuff mid way through your process.
You start the progress indicator spinning ( or whatever version you prefer ) and it shows busy without a specific percentage.
You do your stuff.
When complete, you hide your progress indicator.
Hope that helps.
Technet articles: WPF: Layout Lab; All my Technet Articles
Saturday, February 20, 2016 4:41 PM | 1 vote
The approach I usually use is to make a progress indicator indeterminate.
With that you don't need any fancy stuff mid way through your process.You start the progress indicator spinning ( or whatever version you prefer ) and it shows busy without a specific percentage.
You do your stuff.
When complete, you hide your progress indicator.
Hope that helps.
Im gonna try splitting it in chunks of x bytes and update progress after each part and seee if that works.
If not and i don't find any alternative im gonna have to use a Marquee that would be...
But the whole point was to show visual progress (specially for large files).
Guess nobody wants what i want or it can be done in multiple parts,or there is a other way but not that some one knows here
anyway im gonna keep trying and will report results here before thursday.
Kind Regards !
Saturday, February 20, 2016 5:03 PM
Most prefer a standard busy indicator approach used throughout a project.
The problem with giving a specific percentage is that it's often difficult to get that to work well.
You might have seen the sort of issue when installing software.
There's a progress bar which shoots across to say 30% then it sits there for ever.
You're looking at it wondering what's going on and whether the flippin thing crashed or something.
Then it suddenly shoots up to 100% and it's done.
This is because it's difficult to work out how long some processes will take.
With others you just know it's started and when you get the result, you simply can't tell how long.
You might be able to do chunks at a time with this process so you might be able to make this work ok.
But the trend is to use indeterminate indicators like spinners or the windows 8 spinning balls thing.
Hope that helps.
Technet articles: WPF: Layout Lab; All my Technet Articles
Friday, February 26, 2016 6:47 PM
Hello dear users,
So whenever i could make time i did and worked towards finding an answer to my demand and i found it asynchronously !
I found out that BackgroundWorker couldn't handle the task while debugging (UI freezes and so on)
So i started looking into async and threading.
Async got my attention and after getting a "handle" of it (im new to programming since couple of months)i started to think of a way to achieve my goal.
AND YOU CAN NOT IMAGINE HOW HAPPY I WAS SEEING THAT CIRCLE OFF PROGRESS COMPLETE ITSELF !!!!(im using custom user control iTalk_ProgressBar from HazelDev)
Here's what i did for those that wanna know.
My class with Encryption method has changed to this :
int percentageCounter = 0; // ADDED
long incrementCounter; // ADDED
long lastUpdateCounter = 0; // ADDED
try
{
RijndaelManaged RM = new RijndaelManaged();
UnicodeEncoding UE = new UnicodeEncoding();
string VI = VIkey; // max length 8 !
string CustPass = pass; // max length 16 !
byte[] VIK = UE.GetBytes(VI);
byte[] key = UE.GetBytes(CustPass);
RM.Key = key;
RM.IV = VIK;
ICryptoTransform encryptor = RM.CreateEncryptor(RM.Key, RM.IV);
string cryptFile = outputFile;
using (FileStream fsOut = new FileStream(cryptFile, FileMode.Create))
{
using (CryptoStream cs = new CryptoStream(fsOut, RM.CreateEncryptor(RM.Key, RM.IV),
CryptoStreamMode.Write))
{
using (FileStream fsIn = new FileStream(inputFile, FileMode.Open))
{
incrementCounter = fsIn.Length / 100; // ADDED
int data;
while ((data = fsIn.ReadByte()) != -1)
{
cs.WriteByte((byte)data);
// ADDED WHOLE IF CHECK
if (fsIn.Position >= lastUpdateCounter + incrementCounter)
{
percentageCounter++;
lastUpdateCounter += incrementCounter;
updateProg(percentageCounter,progressBar);
}
}
}; // using filestream input file
} // using Cryptostream
} // using filestream output file
}
catch (Exception ex )
{
MessageBox.Show("Failed to Encrypt File !"+ ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
UpdateProg() is updating the progressbar with value.
When calling await EncryptAsync(); in my code :
private async Task EncryptAsync()
{
await Task.Run(new Action(Encrypt));
MessageBox.Show("File Encrypted succesfully !", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
Where Encrypt() is where i actually calling my encryption method from my class.
So im verry happy it is solved as i wanted it to be :) and i wanna thank everybody who has helped me with provided information and suggestions !!!!
I wish you all a good day !
Kind regards !