I am exporting a Data Table to excel file using background worker. And I wanted to show the export progress using progress bar. Do we have to write the exporting code in Do Work event or can we call a method, which is present in other class.
In my code I tried calling different method. But its not working.
Below is the sample code.
public MainWindow()
{
InitializeComponent();
property = new Property();
this.DataContext = property;
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
System.Windows.Forms.MessageBox.Show(e.Error.Message);
}
else
{
System.Windows.Forms.MessageBox.Show("Exported Successfully");
}
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pbStatus.Value = e.ProgressPercentage;
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
Export export = new Export();
export.GenerateExcelFile();
}
You need to call worker.ReportProgress from worker_DoWork with a valid progress value
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
worker.ReportProgress(0);
// Some job
worker.ReportProgress(10);
// ...
// Finish
worker.ReportProgress(100);
}
I'm not sure how you are generating report. Further I'm supposing your pbStatus has Minimum="0" and Maximum="100". You can after exporting each row report progress something like that.
worker.ReportProgress(currentRow * 100.0 / totalRows);
You also set your progress bar intermediate if you are not sure how to calculate that by setting progress.IsIndeterminate to true
pbStatus.IsIndeterminate = true;
Related
I am practicing to use BackgroundWorker to do some time-consuming jobs.
My goal is showing all the file paths on UI.
I press the RUN button and press the CANCEL button after executing it for 5 seconds. It works fine.
Then I repeat the above steps, I notice that "Check_File" is executed for the third time.
I think that it shall be only two times.
The UI shows like below:
Searching for Files → Many FileName Appear → Canceled
Searching for Files → Many FileName Appear → Searching for Files → Canceled
The following is my code:
private void Run_Click(object sender, RoutedEventArgs e)
{
worker.WorkerSupportsCancellation = true;
worker.WorkerReportsProgress = true;
worker.DoWork += Worker_DoWork;
worker.ProgressChanged += Worker_ProgressChanged;
worker.RunWorkerAsync(PText.Text);
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
FLabel.Content = "Canceled";
}
else
{
FLabel.Content = "Finish";
}
worker.Dispose();
}
private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
FLabel.Content = e.UserState.ToString();
}
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
Check_File("My_Folder_Path", (String)e.Argument, e);
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
worker.CancelAsync();
}
public void Check_File(string Path, string FindStr, DoWorkEventArgs e)
{
string v_alert;
i += 1;
try
{
if (Path.LastIndexOf('\\') != Path.Length)
{
Path = string.Concat(Path, "\\");
}
if (Directory.Exists(Path))
{
worker.ReportProgress(0, string.Concat("Searching for Files...", i.ToString()));
string[] Files = Directory.GetFiles(Path);
if (Files.Length != 0)
{
foreach (string f in Files)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
worker.ReportProgress(Array.IndexOf(Files, f) / Files.Length * 100, f);
}
}
}
else
{
v_alert = string.Concat("No Path:", Path);
MessageBox.Show(v_alert);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Everytime you press the button you add an event to the worker.
private void Run_Click(object sender, RoutedEventArgs e)
{
worker.WorkerSupportsCancellation = true;
worker.WorkerReportsProgress = true;
worker.DoWork += Worker_DoWork; //<----Happens here
worker.ProgressChanged += Worker_ProgressChanged;
worker.RunWorkerAsync(PText.Text);
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
}
So if you press it once. The worker has one event attached. If you press it a second time, the worker get attached another event. Hes now has two events. Hes runs again (this time with 2 events) and there is a total of three runs.
You should set up the worker somewhere else.
public Form1()
{
InitializeComponent();
//Init the worker here...
worker.WorkerSupportsCancellation = true;
worker.WorkerReportsProgress = true;
worker.DoWork += Worker_DoWork;
worker.ProgressChanged += Worker_ProgressChanged;
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
}
private void Run_Click(object sender, RoutedEventArgs e)
{
//only run the worker here
worker.RunWorkerAsync(PText.Text);
}
As Shocky mentioned in the comments, you could also remove the existing event before you attach a new one.
i am working on project in C# and its contain a methods that need a long time to be executed so i need a progress bar that tell the user about how much remain and i don't know how .
i google for it and i see courses about BackgroundWorker and still don't know how to use it
private void Lock_Methods()
{
foreach (FolderInfo fi in FolderInfo)
{
// code need a lot of time ....
}
}
any help please ...
Declare
var bw = new BackgroundWorker()
{ WorkerReportsProgress = true };
bw.RunWorkerAsync();
bw.DoWork += bw_DoWork;
bw.ProgressChanged += bw_ProgressChanged;
And
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
for(int i = 0: i < FolderInfo.Count; i++)
{
//...
(sender as BackgroundWorker).ReportProgress((int)(100/FolderInfo.Count)*i, null);
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
background worker in asp.net does not write the content to the web UI when background worker completed. please tell me the reasons why. and how to recover.???
static BackgroundWorker bwProcess;
[WebMethod()]
public static int GetProgress()
{
return Percentage;
}
background worker starts when click event happen
protected void btnClick_Click(object sender, EventArgs e)
{
bwProcess = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
bwProcess.DoWork += new DoWorkEventHandler(bwProcess_DoWork);
bwProcess.ProgressChanged += new ProgressChangedEventHandler(bwProcess_ProgressChanged);
bwProcess.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwProcess_RunWorkerCompleted);
bwProcess.RunWorkerAsync("AsyncWorker");
}
do work event for the backgroundworker
void bwProcess_DoWork(object sender, DoWorkEventArgs e)
{
bwProcess.ReportProgress(1);
for (int i = 0; i <= 100; i++)
{
if (bwProcess.CancellationPending)
{
e.Cancel = true;
return;
}
bwProcess.ReportProgress(i);
Thread.Sleep(20);
}
e.Result = "100 %";
}
this part is not working. it run nut there is no response
void bwProcess_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Response.WriteFile("D:\\Samples.xlsx");
}
You've passed something to e.Result in DoWork, but you don't anything with it in RunWorkerCompleted.
void bwProcess_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var text = e.Result as string;
Response.Write(text);
Response.WriteFile("D:\\Samples.xlsx");
}
I want to know how to show image loading progress in progress-bar in win form.
my code is
private void Form2_Load(object sender, EventArgs e)//load form and get profile and avatar
{
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
label2.Text = "Avatar Loaded";
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)//showing progress
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => backgroundWorker1_ProgressChanged(sender, e)));
}
else
{
if (progressBarX1.Value != e.ProgressPercentage)
{
progressBarX1.Value = e.ProgressPercentage;
progressBarX1.Refresh();
}
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)//loading avatar
{
WebClient wc = new WebClient();
Stream stream = wc.OpenRead("http://avatar.nimbuzz.com/getAvatar?jid=" + textBox1.Text);
pictureBox1.Image = (Image.FromStream(stream));
}
The image loads successfully but do not show any progress in progress-bar
Well, i would use the ProgressChanged Event from a WebClient to get the result of how far the download progress actually is. Then you can't save it from the thread of the backgroundworker, so you gotta do this when you have the file.
UPDATED
private BackgroundWorker bgw;
private void Form1_Load(object sender, EventArgs e)
{
bgw = new BackgroundWorker();
bgw.DoWork += bgw_DoWork;
bgw.WorkerReportsProgress = true;
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;
bgw.ProgressChanged += bgw_ProgressChanged;
bgw.RunWorkerAsync();
}
void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
pictureBox1.Image = (Image)e.Result;
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
WebClient wc = new WebClient();
wc.DownloadProgressChanged += wc_DownloadProgressChanged;
Stream stream = wc.OpenRead("" + textBox1.Text);
e.Result = (Image.FromStream(stream));
}
void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
bgw.ReportProgress(e.ProgressPercentage);
}
The problem with your code is that backgroundWorker1_ProgressChanged() is called in the context of the worker thread but UI updates can only be done within the UI thread (main thread). In your scenario you must call:
progressBarX1.Value = e.ProgressPercentage;
within the UI thread. There are many ways how to do this but a simple one is to use InvokeReqzired() to check if you are in the UI thread and you are not then call BeginInvoke() to send the execution of that command to the UI-/main-thread. The following should do the trick:
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => backgroundWorker1_ProgressChanged(sender, e)));
}
else
{
progressBarX1.Value = e.ProgressPercentage;
}
}
Update:
I would also change:
backgroundWorker1.RunWorkerAsync();
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
to:
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerAsync();
so the progress event is assigned (and therefore in place) before starting the asynchronous work. Otherwise you may miss a progress call.
Update 2:
You also need the following line to execute in the UI thread:
pictureBox1.Image = (Image.FromStream(stream));
To do so use the Completed event of BackgroundWorker and bass the image data using the result parameter. Then in the eventhandler use InvokeRequired() and BeginInvoke() just like in the Progress event).
Uodate 3:
Remeins unchanged is good as you don't get a crash because of not calling UI stuff in the UI thread ;-)
Try to force a repaint on the control by calling:
progressBarX1.Refresh();
(just after you assigned a new value to it).
So the code in the progress event looks like this:
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => backgroundWorker1_ProgressChanged(sender, e)));
}
else
{
if (progressBarX1.Value != e.ProgressPercentage)
{
progressBarX1.Value = e.ProgressPercentage;
progressBarX1.Refresh();
}
}
}
If that still doesn't work check that your main/UI thread is not blocked or totally busy.
Update 4:
Just to make sure: you need to enable progress-reporting on the background worker and call its ReportProgress() method from time to time within the backgroundWorker1_DoWork(). See the following MS-Tutorial for more information on usage of the BackgroundWorker: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
Enabling progress reporting on a backgroundworker:
backgroundWorker1.WorkerReportsProgress = true;
or use the form-designer and set the property WorkerReportsProgress to True. Then you still need to call the backgroundWorker1.ReportProgress() from time to time.
Update 5:
Ok, lets give it a complete try. I've checked some reference docs from MS so in case of the backgroundworker ProgressChanged and Completed events you don't need to BeginInvoke() them as MS does this already for you.
private void Form2_Load(object sender, EventArgs e)
{
getto();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.ProgressChanged -= backgroundWorker1_ProgressChanged;
backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
backgroundWorker1.RunWorkerCompleted -= backgroundWorker1_Completed;
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_Completed;
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
using (var wc = new WebClient())
{
wc.DownloadProgressChanged += (sender, e) => backgroundWorker1.ReportProgress(sender, e);
using (var stream = wc.OpenRead("http://avatar.nimbuzz.com/getAvatar?jid=" + textBox1.Text))
{
e.Result = (Image.FromStream(stream));
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
progressBarX1.Value = e.ProgressPercentage;
progressBarX1.Refresh();
}
private void backgroundWorker1_Completed(object sender, DoWorkEventArgs e)
{
pictureBox1.Image = e.Result;
}
i need to upload records from excel sheet to sql server
while uploading i need to show the progress in devexpress progress bar
and that too in a manner like uploading 1 out of 100 and it should increment until it finishes
Create a BackgroundWorker and report progress back to the main GUI Thread. Then update the progress bar value with the status coming from the BackgroundWorker.
Here is an example, it uses a common WinForms ProgressBar instead of a DevExpress ProgressBar but the principle is just the same.
public partial class Progress : Form
{
readonly BackgroundWorker _worker = new BackgroundWorker();
public Progress()
{
InitializeComponent();
_worker.WorkerReportsProgress = true;
_worker.DoWork += _worker_DoWork;
_worker.ProgressChanged += WorkerProgressChanged;
_worker.RunWorkerCompleted += WorkerRunWorkerCompleted;
_worker.RunWorkerAsync();
}
private void _worker_DoWork(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
// Simulate work (uploading Excel records to SQL Server)
for (var i = 1; i <= 100; i++)
{
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
// Upload some data here, Sleep(100) is just an example
Thread.Sleep(100);
// Calculate current progress and report
worker.ReportProgress(i);
}
}
void WorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
_progressBar.Value = e.ProgressPercentage;
}
void WorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_progressBar.Value = 0;
}
}