how to report about method situation via progress bar wpf C# - c#

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;
}

Related

C# WPF Progress bar not fully updating with background worker

I am working on a program that gets the MD5 hash signature from files that the user has selected then run it through a text file of well-known virus md5 and checks for a match. What I came to realize is that some files take a bit of time to convert. I have attempted to get a progress bar to work but have an issue where I only get it to update when it has finished and it ignores my other report progress. Any help appreciated
Here is the code for the Progress bar:
private void Border_MouseLeftButtonDown_1(object sender, MouseButtonEventArgs e)
{
this.Dispatcher.Invoke((Action)(() =>
{
BackgroundWorker scanner = new BackgroundWorker();
scanner.RunWorkerCompleted += scanner_RunScannerCompleted;
scanner.WorkerReportsProgress = true;
scanner.DoWork += scanner_Scan;
scanner.ProgressChanged += scanner_ProgressChanged;
scanner.RunWorkerAsync();
}));
}
private void scanner_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.Dispatcher.Invoke((Action)(() =>
{
progressBar.Value = e.ProgressPercentage;
}));
}
private void scanner_Scan(object sender, DoWorkEventArgs e)
{
this.Dispatcher.Invoke((Action)(() =>
{
var scanner = sender as BackgroundWorker;
scanner.ReportProgress(0);
scanner.ReportProgress(10);
scanner.ReportProgress(20);
getMD5(tbFilePath.Text);
scanner.ReportProgress(80);
checkSignatures();
scanner.ReportProgress(100);
}));
}
private void scanner_RunScannerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Dispatcher.Invoke((Action)(() =>
{
MessageBox.Show("Scan Complete");
progressBar.Value = 0;
}));
}
I have already tried to add the "this.Dispatcher.Invoke" as I have already seen from other pages that this should fix the issue but hasn't for me.

Can we call method in DoWork event?

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;

how to return from the background worker to web UI in asp.net

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");
}

How Do I Show Image Loading Progress in progress-bar c#

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;
}

Exception when update a progressbar in a Background Worker

I created a wpf application.
In my application, i open a windows and i copy in background some files.
I would like to display and update a progressbar during thos copy.
I tried to use a BackgroundWorker :
public partial class FenetreProgressBar : Window
{
private readonly BackgroundWorker worker = new BackgroundWorker();
public FenetreProgressBar(ObservableCollection<Evenement.FichierJoint> CollectionFicJointsToAdd)
{
InitializeComponent();
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.ProgressChanged +=worker_ProgressChanged;
worker.RunWorkerAsync(CollectionFicJointsToAdd);
}
private void ProgressChanged(double Persentage, ref bool Cancel)
{
if (Cancel)
this.Close();
worker.ReportProgress((int)Persentage);
}
private void Completedelegate()
{
this.Close();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
ObservableCollection<Evenement.FichierJoint> collection = e.Argument as ObservableCollection<Evenement.FichierJoint>;
//2) On ajoute les fichiers joints à l'évènements ( ce qui va donc les copier dans le répertoire paramétré)
foreach (Evenement.FichierJoint FichierJoint in collection)
{
if (FichierJoint.strPathFichier.Length > 0)
{
Evenement.FichierJoint monFichierJoint = new Evenement.FichierJoint(FichierJoint.strPathFichier, App.obj_myEvenement.strEvtNumeroString);
MaProgressBar.Minimum = 0;
MaProgressBar.Maximum = 100;
monFichierJoint.copyObject.OnProgressChanged += ProgressChanged;
monFichierJoint.copyObject.OnComplete += Completedelegate;
monFichierJoint.AddFichierJoint();
}
}
}
private void worker_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
{
// Traitement terminé, on ferme la fenetre
this.Close();
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
MaProgressBar.Value = e.ProgressPercentage;
}
}
When the programme go here :
MaProgressBar.Minimum = 0;
MaProgressBar.Maximum = 100;
I have an exception : " The calling thread cannot access this object because a different thread owns it".
I have read severals answer on google and stackoverflow but i don't try to use this approach with the BackgroundWorker.
Anyone coule help me in order to avoid this exception and solve the problem please ?
Thanks a lot,
Best regards :)
You cannot modify UI objects from background worker. You need to invoke the methods on UI dispatcher like this -
App.Current.Dispatcher.Invoke((Action)delegate
{
MaProgressBar.Minimum = 0;
MaProgressBar.Maximum = 100;
});
But since you only need to set maximum an minimum values, i would suggest you to set these values outside of backgroundWorker in constructor -
public FenetreProgressBar(ObservableCollection<Evenement.FichierJoint>
CollectionFicJointsToAdd)
{
InitializeComponent();
MaProgressBar.Minimum = 0;
MaProgressBar.Maximum = 100;
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.ProgressChanged +=worker_ProgressChanged;
worker.RunWorkerAsync(CollectionFicJointsToAdd);
}
Why don't you use C# new async and await new feature/keywords? they were specifically designed to make the UI responsive while doing lengthy operations.
You should try this:
_backgroundWorker.OnProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
and then
// Event handler
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Update main thread here
}

Categories

Resources