I've a background worker that calling a recursive subroutine that traverse a directory, subdirectory and populate the file names into an array. I've a backgroundworker process that is doing this and this also return the percent. I also have a public string dirName that contain the current directory at any given moment and I want it to display together with the percentage (e.g. Processing dirName....nn%), how do I do that?
void m_bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pictureBox1.Visible = true;
pictureBox1.Refresh();
progressBar1.Value = e.ProgressPercentage;
lblStatus.Text = "Processing + dirName + "....." + progressBar1.Value.ToString() + "%";
}
void m_bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
if (m_bgWorker.CancellationPending)
{
e.Cancel = true;
m_bgWorker.ReportProgress(0);
return;
}
else
{
//e.Result containing an array of directories
e.Result = processFile(pgmName, pgmPath, worker, e);
}
m_bgWorker.ReportProgress(100);
}
In your processFile() method, you'd report progress and pass back the directory using the overload of ReportProgress() that takes an object:
int progress = 0;
string directory = "C:\Foo\Bazz";
while(...)
{
//...
//...
m_bgWorker.ReportProgress(progress, directory);
}
Then in your m_bgWorker_ProgressChanged(), you'd do this to get the directory out:
void m_bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pictureBox1.Visible = true;
pictureBox1.Refresh();
progressBar1.Value = e.ProgressPercentage;
string dirName = e.UserState.ToString();
lblStatus.Text = "Processing" + dirName + "....." + progressBar1.Value.ToString() + "%";
}
A great resource for learning more about BackgroundWorker is Joseph Albahari's page on the class, which is a part of a larger article on threading in C#.
Related
Can anyone tell me if it is possible(and give an example if it is) on how to have a progress bar(and status label if possible) showing the progress of a ZIP file being extracted using "ZipFile"(Ionic.zip, http://dotnetzip.codeplex.com/)?
My WinForm does a great job at extracting a ZIP file from my chosen path to a new path no worries at all using textboxes and browse buttons and all that jazz... However the only issue is i cannot use anything on my form during this time it is as if it has frozen, but its only because its unzipping the ZIP file in the background.
The ZIP file is a big file and i would like to make it less confusing on what is going on by adding and having a progress bar showing how the unzipping is going with a accurate ETA.
Surely this is possible, i just cannot work out how to do it in C# WinForms, i have had a fairly decent look all around the net without really being able to come across a example i can find suitable for me.
Here is a rough example of what i have:
private void button1_Click(object sender, EventArgs e)
{
var ROBOT0007 = textBox1.Text + #"\" + "ROBOT0007"; //ROBOT0007 folder
var ROBOT_INSTALL = textBox1.Text + #"\" + "911" + #"\" + "files"; //ROBOT0007/911/files
var ROBOT_INSTALL_SPECIAL = ROBOT_INSTALL + #"\" + "special.rar"; //ROBOT0007/911/files/special.rar
//If the path has text...
if (textBox1.TextLength > 0)
{
//if the subfolder doesn't exist then make it.
if (!Directory.Exists(ROBOT0007))
{
Directory.CreateDirectory(ROBOT0007);
}
//if the textbox directory exists
if (Directory.Exists(ROBOT0007))
{
using (ZipFile zip = ZipFile.Read(ROBOT_INSTALL_SPECIAL))
{
zip.ExtractAll(ROBOT0007, ExtractExistingFileAction.OverwriteSilently);
}
}
}
}
UPDATE(04/11/2014): I have removed the textbox for now gone back to simple basics, the following works with a background worker, however the cancel button has no effect on RAR files... any advice?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Threading;
using System.Text;
using System.Windows.Forms;
using Ionic.Zip;
using System.IO;
namespace BackgroundWorkerSample
{
// The BackgroundWorker will be used to perform a long running action
// on a background thread. This allows the UI to be free for painting
// as well as other actions the user may want to perform. The background
// thread will use the ReportProgress event to update the ProgressBar
// on the UI thread.
public partial class Form1 : Form
{
/// <summary>
/// The backgroundworker object on which the time consuming operation
/// shall be executed
/// </summary>
BackgroundWorker backgroundWorker1;
public Form1()
{
InitializeComponent();
backgroundWorker1 = new BackgroundWorker();
// Create a background worker thread that ReportsProgress &
// SupportsCancellation
// Hook up the appropriate events.
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler
(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler
(backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
}
/// <summary>
/// On completed do the appropriate task
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// The background process is complete. We need to inspect
// our response to see if an error occurred, a cancel was
// requested or if we completed successfully.
if (e.Cancelled)
{
lblStatus.Text = "Task Cancelled.";
}
// Check to see if an error occurred in the background process.
else if (e.Error != null)
{
lblStatus.Text = "Error while performing background operation.";
}
else
{
// Everything completed normally.
lblStatus.Text = "Task Completed...";
}
//Change the status of the buttons on the UI accordingly
btnStart.Enabled = true;
btnCancel.Enabled = false;
}
/// <summary>
/// Notification is performed here to the progress bar
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// This function fires on the UI thread so it's safe to edit
// the UI control directly, no funny business with Control.Invoke :)
// Update the progressBar with the integer supplied to us from the
// ReportProgress() function.
progressBar1.Value = e.ProgressPercentage;
lblStatus.Text = "Processing......" + progressBar1.Value.ToString() + "%";
}
/// <summary>
/// Time consuming operations go here </br>
/// i.e. Database operations,Reporting
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// The sender is the BackgroundWorker object we need it to
// report progress and check for cancellation.
//NOTE : Never play with the UI thread here...
for (int i = 0; i < 100; i++)
{
//Thread.Sleep(100);
string INSTALL_FOLDER= "C:" + #"\" + "Program Files (x86)" + #"\" + "Robot91111"+ #"\" + "basic" + #"\" + "string" + #"\" + "special.rar";
string BURGOS_FOLDER = "C:" + #"\" + "Program Files (x86)" + #"\" + "Robot91111" + #"\" + "Burgos_Folder";
if (!Directory.Exists(BURGOS_FOLDER))
{
Directory.CreateDirectory(BURGOS_FOLDER);
using (ZipFile zip = ZipFile.Read(INSTALL_FOLDER))
{
zip.ExtractAll(BURGOS_FOLDER, ExtractExistingFileAction.OverwriteSilently);
}
}
// Periodically report progress to the main thread so that it can
// update the UI. In most cases you'll just need to send an
// integer that will update a ProgressBar
backgroundWorker1.ReportProgress(i);
// Periodically check if a cancellation request is pending.
// If the user clicks cancel the line
// m_AsyncWorker.CancelAsync(); if ran above. This
// sets the CancellationPending to true.
// You must check this flag in here and react to it.
// We react to it by setting e.Cancel to true and leaving
if (backgroundWorker1.CancellationPending)
{
// Set the e.Cancel flag so that the WorkerCompleted event
// knows that the process was cancelled.
e.Cancel = true;
backgroundWorker1.ReportProgress(0);
return;
}
}
//Report 100% completion on operation completed
backgroundWorker1.ReportProgress(100);
}
private void btnStartAsyncOperation_Click(object sender, EventArgs e)
{
//Change the status of the buttons on the UI accordingly
//The start button is disabled as soon as the background operation is started
//The Cancel button is enabled so that the user can stop the operation
//at any point of time during the execution
btnStart.Enabled = false;
btnCancel.Enabled = true;
// Kickoff the worker thread to begin it's DoWork function.
backgroundWorker1.RunWorkerAsync();
}
private void btnCancel_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy)
{
// Notify the worker thread that a cancel has been requested.
// The cancel will not actually happen until the thread in the
// DoWork checks the backgroundWorker1.CancellationPending flag.
backgroundWorker1.CancelAsync();
}
}
}
}
/*...*/
using (ZipFile zip = ZipFile.Read(ROBOT_INSTALL_SPECIAL))
{
zip.ExtractProgress +=
new EventHandler<ExtractProgressEventArgs>(zip_ExtractProgress);
zip.ExtractAll(ROBOT0007, ExtractExistingFileAction.OverwriteSilently);
}
/*...*/
void zip_ExtractProgress(object sender, ExtractProgressEventArgs e)
{
if (e.TotalBytesToTransfer > 0)
{
progressBar1.Value = Convert.ToInt32(100 * e.BytesTransferred / e.TotalBytesToTransfer);
}
}
private int totalFiles;
private int filesExtracted;
/*...*/
using (ZipFile zip = ZipFile.Read(ROBOT_INSTALL_SPECIAL))
{
totalFiles = zip.Count;
filesExtracted = 0;
zip.ExtractProgress += ZipExtractProgress;
zip.ExtractAll(ROBOT0007, ExtractExistingFileAction.OverwriteSilently);
}
/*...*/
private void ZipExtractProgress(object sender, ExtractProgressEventArgs e)
{
if (e.EventType != ZipProgressEventType.Extracting_BeforeExtractEntry)
return;
filesExtracted++;
progressBar.Value = 100 * filesExtracted / totalFiles;
}
using System.IO.Compression;
private async void Unzip(string filePath)
{
var _downloadPath = configuration.GetValue("DownloadPath");
var _extractPath = configuration.GetValue("ExtractPath");
var _extractPattern = configuration.GetValue("ExtractPattern");
Console.WriteLine($"Удаление старых файлов из директории: '{_extractPath}'");
var directoryInfo = new DirectoryInfo(_extractPath);
foreach (var file in directoryInfo.GetFiles())
{
file.Delete();
}
Console.WriteLine($"Распаковка файла: '{filePath}'");
var regex = new Regex(_extractPattern);
var fileList = new List();
var totalFiles = 0;
var filesExtracted = 0;
using (var archive = await Task.Run(() => ZipFile.OpenRead(filePath)))
{
foreach (var file in archive.Entries)
{
if (regex.IsMatch(file.Name))
{
fileList.Add(file);
totalFiles++;
}
}
foreach (var file in fileList)
{
Console.WriteLine($"Извлечение файла: '{file.Name}'");
await Task.Run(() =>
{
file.ExtractToFile($"{_extractPath}{file.Name}");
filesExtracted++;
var progress = Convert.ToInt32(100 * filesExtracted / totalFiles);
Console.WriteLine($"Извлечено: {progress}%");
});
}
}
}
appsettings.json example
{
"DownloadPath": "f:\\download\\",
"ExtractPath": "f:\\download\\extract\\",
"ExtractPattern": "ACTSTAT.DBF|CENTERST.DBF|CURENTST.DBF|ESTSTAT.DBF|FLATTYPE.DBF|NDOCTYPE.DBF|OPERSTAT.DBF|ROOMTYPE.DBF|SOCRBASE.DBF|STRSTAT.DBF|[A-Z]{1}16.DBF",
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
using (ZipFile zip = ZipFile.Read(#"edu.zip"))
{
totalFiles = zip.Count;
filesExtracted = 0;
zip.ExtractProgress += ZipExtractProgress;
zip.ExtractAll(#"./", ExtractExistingFileAction.OverwriteSilently);
}
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
backgroundWorker1.ReportProgress(0);
return;
}
backgroundWorker1.ReportProgress(100);
}
private void ZipExtractProgress(object sender, ExtractProgressEventArgs e)
{
if (e.EventType != ZipProgressEventType.Extracting_BeforeExtractEntry)
return;
filesExtracted++;
this.Dispatcher.Invoke(new Action(() =>
{
progressBar1.Value = 100 * filesExtracted / totalFiles;
}));
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
status.Content = "extractia a fost anulata";
}
else if (e.Error != null)
{
status.Content = "Ceva nu a mers ";
}
}
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
status.Content = "Se dezarhiveaza......" + progressBar1.Value.ToString() + "%";
}
private void Button_Click(object sender, RoutedEventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
I have the following code, I'm trying to open a directory and process the files in it via the Background worker but I am having issues with it.
The error I have is (The name filePath does not exist in the current context), which I can understand because it's stored in another method? if someone could point out to me what is wrong with my code it would be appreciated. Folderbrowser doesn't work under the Background worker section.
private void btnFiles_Click(object sender, EventArgs e)
{
//btnFiles.Enabled = false;
btnSTOP.Enabled = true;
//Clear text fields
listBoxResults.Items.Clear();
listBoxPath.Items.Clear();
txtItemsFound.Text = String.Empty;
//Open folder browser for user to select the folder to scan
DialogResult result = folderBrowserDialog1.ShowDialog();
if (result == DialogResult.OK)
{
//Store selected folder path
string filePath = folderBrowserDialog1.SelectedPath;
}
//Start the async operation here
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//Process the folder
try
{
foreach (string dir in Alphaleonis.Win32.Filesystem.Directory.EnumerateFiles(filePath, "*.*", SearchOption.AllDirectories, true))
{
//Populate List Box with all files found
this.Invoke(new Action(() => listUpdate2(dir)));
FileInfo fi = new FileInfo(dir);
if (fi.Length == 0)
{
//Populate List Box with all empty files found
this.Invoke(new Action(() => listUpdate1(dir + Environment.NewLine)));
}
}
}
//Catch exceptions
catch (Exception err)
{
// This code just writes out the message and continues to recurse.
log.Add(err.Message);
//throw;
}
finally
{
//add a count of the empty files here
txtItemsFound.Text = listBoxResults.Items.Count.ToString();
// Write out all the files that could not be processed.
foreach (string s in log)
{
this.Invoke(new Action(() => listUpdate1(s)));
}
log.Clear();
MessageBox.Show("Scanning Complete", "Done", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
//If cancel button was pressed while the execution is in progress
//Change the state from cancellation ---> cancelled
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
//backgroundWorker1.ReportProgress(0);
return;
}
//}
//Report 100% completion on operation completed
backgroundWorker1.ReportProgress(100);
}
#DonBoitnott solution is the most general for data flow inside class. Specifically to BackgroundWorker there is another one exists
private void btnFiles_Click(object sender, EventArgs e)
{
...
// pass folder name
backgroundWorker1.RunWorkerAsync(folderBrowserDialog1.SelectedPath);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// get passed folder name
string filePath = (string)e.Argument;
...
}
The variable "filePath" is being declared local to the btnFiles_Click method. In order for it to be used elsewhere, it must be declared global to the code page:
public class Form1
{
private String _filePath = null;
private void btnFiles_Click(object sender, EventArgs e)
{
//get your file and assign _filePath here...
_filePath = folderBrowserDialog1.SelectedPath;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//use _filePath here...
}
}
private bool ImportData()
{
bool result = false;
try
{
intdevid = int.Parse(cmbDeviceName.SelectedValue.ToString());
FetchDevicedata(intdevid);
//FTPTCompletedBatchTransfer();
FetchMaxReportId();
GetFTPFile(strDeviceIP, strDeviceUsername, strDevicePwd, strDevicePath + "//RunningBatch//RunningBatch.db", "RunningBatch.db"); // Copy RunningBatch.db to Debug Folder from Remote
LoadRunningData(); // Get Running Data in dataset from running.db
if (DecodeBatchData_R() == false)
{
MessageBox.Show("Running Batch Data Not Found");
}// save in batch master and row data table
GetFTPFile(strDeviceIP, strDeviceUsername, strDevicePwd, strDevicePath + "//CompletedBatch//CompletedBatch.db", "CompletedBatch.db");
LoadCompletedData();
if (DecodeBatchData() == false)
{
MessageBox.Show("Completed Batch Data not found");
}
result = true;
}
catch (Exception ex)\\here error:Cross-thread operation not valid: Control 'cmbDeviceName' accessed from a thread other than the thread it was created on.
{
clsLogs.LogError("Error: " + ex.Message + this.Name + " || ImportData");
result = false;
}
return result;
}
private void btnimport_Click(object sender, EventArgs e)
{
//////////////////copy checkweigher .db to database folder
dsCheckRptId = new DataSet();
///////////////////////////////////////////////////////////
if (cmbDeviceName.Text.ToString().Trim() == "--Select--")
{
MessageBox.Show("Please Select Proper Device");
cmbDeviceName.Focus();
return;
}
var deviceId = (int)cmbDeviceName.SelectedValue;
bgw.RunWorkerAsync(deviceId);
progressBar1.Visible = true;
label2.Visible = true;
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 100; i++)
{
var deviceId = (int)e.Argument;
e.Result = ImportData();
System.Threading.Thread.Sleep(100);
bgw.ReportProgress(i);
}
}
void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
label2.Text = String.Format("Progress: {0} %", e.ProgressPercentage);
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var result = (bool)e.Result;
if (cmbDeviceName.SelectedValue != null && cmbDeviceName.SelectedValue.ToString().Trim() != "0" && cmbDeviceName.SelectedValue.ToString().Trim() != "System.Data.DataRowView" && cmbDeviceName.SelectedValue.ToString().Trim() != "")
if (result)
{
MessageBox.Show("Data Import Completed Successfully for " + strDevicename);
clsLogs.LogEvent(3, "Data Import Completed Successfully for " + strDevicename);
}
else
{
MessageBox.Show("Data Import Fail For " + strDevicename);
clsLogs.LogEvent(3, "Data Import Fail for " + strDevicename);
}
progressBar1.Visible = false;
label2.Visible = false;
}
;When I run this background worker coding, there's an error stating "Cross-thread operation not valid: Control 'cmbDeviceName' accessed from a thread other than the thread it was created on. ."
How do I solve this problem guys?
WinForms controls are not thread safe, thus cross-thread operations on controls are not valid. You can access controls only from thread which created those controls. In your code you are accessing cmbDeviceName combobox from background thread. Best option to solve this is passing intdevid as RunWorkerAsync argument:
// executed on main thread
var deviceId = (int)cmbDeviceName.SelectedValue;
backgroundWorker.RunWorkerAsync(deviceId);
And get this argument in your DoWork handler:
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// executed on background thread
var deviceId = (int)e.Argument;
// ...
}
Suggested reading: Safe, Simple Multithreading in Windows Forms
I have a situation where all I need is a label that switches between "Ready" and "In progress" when a user clicks a button. The label is intially in the "Ready" state. When the user clicks a button, the label should read "In progress" then some tasks need to be performed, like copying files etc. After the tasks are completed successfully the label should once again read "Ready". Right now I am using this piece of code and the label status does not change. How can I make this work. Please help.
private void button1_Click(object sender, EventArgs e)
{
status.Text = "In Progress";
if (listBox1.Items.Count == 0)
{
MessageBox.Show("Please select a file to upload");
}
FtpClient client = new FtpClient("*******", "*******", "******");
string fileName = getFileNameFromPath(listBox1.Items[0].ToString());
string localFile = listBox1.Items[0].ToString();
string remoteFile = "**********/"+fileName;
string link = client.upload(remoteFile, localFile);
listBox1.Items.RemoveAt(0);
textBox1.Text = link;
status.Text = "Ready";
}
You're blocking the UI thread during your long running process, both preventing the UI from updating the text value, or receiving user input, or doing anything for that matter.
You need to do the long running work asynchronously so as to not block the UI thread.
Ideally you'd have an asynchronous method provided by your FtpClient (and even better, it would return a Task). This would allow you to write something like this:
private async void button1_Click(object sender, EventArgs e)
{
status.Text = "In Progress";
if (listBox1.Items.Count == 0)
{
MessageBox.Show("Please select a file to upload");
}
FtpClient client = new FtpClient("*******", "*******", "******");
string fileName = getFileNameFromPath(listBox1.Items[0].ToString());
string localFile = listBox1.Items[0].ToString();
string remoteFile = "**********/" + fileName;
string link = await client.uploadAsync(remoteFile, localFile);
listBox1.Items.RemoveAt(0);
textBox1.Text = link;
status.Text = "Ready";
}
And then you'd be done. If it doesn't provide any asynchronous methods then, as a work around, you can just start up a new task to do the work in the background:
private async void button1_Click(object sender, EventArgs e)
{
status.Text = "In Progress";
if (listBox1.Items.Count == 0)
{
MessageBox.Show("Please select a file to upload");
}
FtpClient client = new FtpClient("*******", "*******", "******");
string fileName = getFileNameFromPath(listBox1.Items[0].ToString());
string localFile = listBox1.Items[0].ToString();
string remoteFile = "**********/" + fileName;
string link = await Task.Run(() => client.upload(remoteFile, localFile));
listBox1.Items.RemoveAt(0);
textBox1.Text = link;
status.Text = "Ready";
}
If you don't have C# 5.0 and .NET 4.5 to be able to use await then you can use a BackgroundWorker:
private void button1_Click(object sender, EventArgs e)
{
status.Text = "In Progress";
if (listBox1.Items.Count == 0)
{
MessageBox.Show("Please select a file to upload");
}
string fileName = getFileNameFromPath(listBox1.Items[0].ToString());
string localFile = listBox1.Items[0].ToString();
string remoteFile = "**********/" + fileName;
var worker = new BackgroundWorker();
worker.DoWork += (s, args) =>
{
FtpClient client = new FtpClient("*******", "*******", "******");
args.Result = client.upload(remoteFile, localFile);
};
worker.RunWorkerCompleted += (s, args) =>
{
listBox1.Items.RemoveAt(0);
textBox1.Text = args.Result as string;
status.Text = "Ready";
};
worker.RunWorkerAsync();
}
In the top of the form i did:
progressBar1.Maximum = 100;
progressBar1.Minimum = 1;
Then in the button click event that start the operation i did:
timer2.Enabled = true;
if (this.backgroundWorker1.IsBusy == false)
{
this.backgroundWorker1.RunWorkerAsync();
}
Then in the backgroundworkerdowork event:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if (filesContent.Length > 0)
{
for (int i = 0; i < filesContent.Length; i++)
{
File.Copy(filesContent[i], Path.Combine(contentDirectory, Path.GetFileName(filesContent[i])), true);
}
}
DoProgressBar(e, worker);
WindowsUpdate();
CreateDriversList();
GetHostsFile();
Processes();
}
All the functions in the DoWork event are copying files the Processes() function use a new class i did that use Process to create/copy files.
Then the new DoProgressBar event function i did:
private static void DoProgressBar(DoWorkEventArgs e, BackgroundWorker worker)
{
for (int i = 1; i <= 90; i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(50);
worker.ReportProgress(i);
}
}
}
Then ProgressChanged event:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
Then the completed event:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((e.Cancelled == true))
{
this.label1.Text = "Canceled!";
}
else if (!(e.Error == null))
{
this.label1.Text = ("Error: " + e.Error.Message);
}
else
{
this.progressBar1.Value = this.progressBar1.Maximum;
processfinish = true;
}
}
Timer2 tick event:
private void timer2_Tick(object sender, EventArgs e)
{
timerCount += 1;
TimerCount.Text = TimeSpan.FromSeconds(timerCount).ToString();
TimerCount.Visible = true;
if (processfinish == true)
{
timer2.Enabled = false;
timer1.Enabled = true;
}
}
And timer1 tick event:
private void timer1_Tick(object sender, EventArgs e)
{
count++;
Diagnose.Text = "PROCESS HAS FINISHED" + " " + countBack--;
if (count == 6)
{
Diagnose.Text = "COLLECT INFORMATION";
Diagnose.Enabled = true;
CreateZip.Enabled = true;
ViewLogFile.Enabled = true;
DriverVerifier.Enabled = true;
timer1.Enabled = false;
TimerCount.Visible = false;
}
}
I know its a long code but everything here is connected.
What i wanted to do is that the progressBar will get progress according to the progress of each function in the DoWork event .
But instead what is it doing now is first going to the :
DoProgressBar() event/function do the second/else part ReportProgress(i)
Then its going to the Progresschanged event and do: progressBar1.Value = e.ProgressPercentage;
The result is when i click the button click to start the opertion i see right away the progress bar moving almost to the end instead moving according to each function/progress of the program.
You can see my complete code of Form1 here:
http://codepaste.net/fuk9w5
EDIT:
This is the code of the class ProcessRun where im using in Form1 in the function Processes()
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.IO;
namespace Diagnostic_Tool_Blue_Screen
{
class ProcessRun
{
public void ProcessesRun()
{
}
public static void Processing(string WorkingDirectory, string FileName, string Arguments, bool StandardOutput, string OutputFileName)
{
Process proc = new Process();
proc.EnableRaisingEvents = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = StandardOutput;
proc.StartInfo.FileName = FileName;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.WorkingDirectory = WorkingDirectory;
proc.StartInfo.Arguments = Arguments;
proc.Start();
if (StandardOutput == true)
{
string output = proc.StandardOutput.ReadToEnd();
DumpOutput(WorkingDirectory + "\\" + OutputFileName, output);
}
proc.WaitForExit();
proc.Close();
}
private static void DumpOutput(string filename, string output)
{
StreamWriter w = new StreamWriter(filename);
w.Write(output);
w.Close();
}
}
}
It appears that your background thread is interacting directly with a UI element (the progress bar). That's a problem. Your background thread can't directly interact with the UI element; it has to invoke it such that the UI update occurs on the UI thread.
You could, for example, add a method like this to your form:
// Form method for updating progress bar; callable from worker thread
public void UpdateProgressBar(double progress)
{
// dispatch the update onto the form's thread
Dispatcher.BeginInvoke((Action<double>)((n) =>
{
// do the update in the form's thread
progressBar1.Value = n;
}), progress);
}
You can then call this method from your worker thread and the progress bar should update properly.
why not put this into your code? This is how I move the "green" part of the progressbar.
progressBar1.Step = pos; //where pos is the number on how much do you want to increase the progress of the progressbar
progressBar1.PerformStep(); //triggers the movement of the progressBar.
For those who ended up here while trying to find a way to change value of progess bar with cross threading this is how you do it:
form.Invoke((Action)delegate { form.function(); });