Update progressbar from a backgroundworker in WPF - c#

I'm trying to make a progressbar advance using a BackgroundWorker. The final goal is to show the progress of a background search, but I first want to get to know the progress bar by doing a simple simulation. This is the code:
public MainWindow()
{
InitializeComponent();
worker = new BackgroundWorker(); // variable declared in the class
worker.WorkerReportsProgress = true;
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Title += " DONE";
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
for(int j = 0; j <= 100; j++)
{
worker.ReportProgress(j);
Title += j.ToString();
Thread.Sleep(50);
}
}
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
searchProgressBar.Value = e.ProgressPercentage;
}
But when I run it, it skips right to the end, without altering the progressbar in any way. When I debug it step-by-step, the last step I get to is worker.ReportProgress(j);, then control returns to the program and worker_RunWorkerCompleted is called. Why?

In case you trying to change the UI content, you should put the calls on UI Dispatcher. You can't modify UI objects from background thread. Replace your lines with these -
App.Current.Dispatcher.Invoke((Action)delegate()
{
Title += j.ToString();
});
and
App.Current.Dispatcher.Invoke((Action)delegate()
{
Title = "Done";
});

You forgot to run the worker:
worker.RunWorkerAsync();

Related

c# progress bar starting at old value on second run

So I have a quick file mover program and it works fine and the progress bar show the right percentage while working but when i run it a second time. The progress bar starts at the last value. Even though I start by updating the progressbar1.value = 0;
Only way to make the progressbar re-start at zero is to close the program and start it again
private void button_move_Click(object sender, RoutedEventArgs e)
{
worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(Worker_DoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(Worker_ProgressChanged);
worker.WorkerReportsProgress = true;
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);
worker.RunWorkerAsync();
}
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
try
{
//neither updating the Value to 0 or ReportProgress to 0 worked
//progressbar1.Value = 0;
//worker.ReportProgress(0);
moveFiles(sender, e, dirFiless);
}
catch (Exception ex)
{
Console.WriteLine("Error trying to Move files: " + ex);
}
}
private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressbar1.Value = e.ProgressPercentage;
progressbar1.Value = e.ProgressPercentage - 1;
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressbar1.Value = 0;
return;
}
//this works and the progress bar gets updated incrementally
public void moveFiles(object sender, DoWorkEventArgs e, string[] dirFiles)
{
totalFiles = dirFiles.Length;
foreach (string file in dirFiles)
{
filecount++;
percentage = (int)((filecount * 100) / totalFiles);
worker.ReportProgress(percentage);
//move file
}
worker.ReportProgress(100);
}
Are you resetting your filecount variable back to 0? In the code you posted it appears that it just keeps counting up with each run which would cause the progress bar to jump back up even after you previously set it back to 0.

wpf c# progress bar wont update untill after work is done when in background worker

below is some code i am using to show a progress bar on window1. However when work is done on my main window the progress bar freezes then jumps to what ever stage the background worker is in. Is there anyway to have the progress bar constantly update. Even if work is being done in other windows
public SplashScreen()
{
InitializeComponent();
//Timer();
CreateBackGroundWorker();
// int shareProgressBarValue = MainSharePage.shareProgressBarValue;
LoginPage LoginPage = new LoginPage();
LoginPage.Show();
}
private void CreateBackGroundWorker()
{
BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerAsync();
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.ProgressBar.Value = e.ProgressPercentage;
//ShareProgressBarText.Text = (string)e.UserState;
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
worker.ReportProgress(0, String.Format("Processing Iteration 1."));
for (int i = 0; i < 100; i++)
{
Thread.Sleep(1000);
worker.ReportProgress((i + 1), String.Format("Processing Iteration {0}.", i + 2));
}
worker.ReportProgress(100, "Done Processing.");
}
I copy-pasted your code and removed the two lines dealing with your LoginPage, and it works flawlessly for me.
I then created and empty window as a replacement for LoginPage, added the same two lines to show it, and it still works.
I'd guess the problem is in your LoginPage, which must be blocking the UI thread one way or another.

How to make a progressbar run in a different thread in C#

I want to create a basic multi-thread application using a progress bar. Meaning that this progress bar will run on a different thread while the main thread is busy in the large process it is doing. I've seen a lot of tutorials about it. But the thing that they are multi-threading is the one that doing the large process. The progress bar in the other form is just showing a simple progress bar that runs and complete using a timer.
This is the code I have now.
For the thread:
public void thread()
{
Form6 for6 = new Form6();
for6.Show();
}
TH1 = new Thread(thread);
TH1.Start();
For the progress bar (Code inside form 6)
private void timer1_Tick(object sender, EventArgs e)
{
progressBar1.Increment(+1);
if (progressBar1.Value == 99)
{
this.Close();
}
}
private void Form6_Load(object sender, EventArgs e)
{
timer1.Start();
}
My problem is the thread in here doesn't run the Form6. Is there any way for me to do this?
Instead of using main thread for large processing you can use the Background worker for all the processing.
Here's a simple example to do it.
public partial class Form1 : Form
{
BackgroundWorker bgw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
label1.Text = "";
label2.Text = "";
}
private void button1_Click_1(object sender, EventArgs e)
{
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
bgw.WorkerReportsProgress = true;
bgw.RunWorkerAsync();
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
int total = 57; //some number (this is your variable to change)!!
for (int i = 0; i <= total; i++) //some number (total)
{
System.Threading.Thread.Sleep(100);
int percents = (i * 100) / total;
bgw.ReportProgress(percents, i);
//2 arguments:
//1. procenteges (from 0 t0 100) - i do a calcumation
//2. some current value!
}
}
void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
label1.Text = String.Format("Progress: {0} %", e.ProgressPercentage);
label2.Text = String.Format("Total items transfered: {0}", e.UserState);
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//do the code when bgv completes its work
}
}
Instead of the ProgressBar, you should really move your long-running, non-UI code into a separate thread. The standard and easier way of doing this in WinForms is to use BackgroundWorker component, which can raise ProgressChanged event where you can update your UI. Important to note that ProgressChanged event is raised on the UI thread, not on the worker thread, so you don't even need to use Invoke() to perform UI operations (such as updating your ProgressBar).
you must use Control.Invoke for avoid cross-threading problem,but I prefer use BackgroundWorker for resolve it, create Form6 on a _field and use progressbar in ProgressChanged event for more information see this page
public void thread()
{
Form6 for6=null;
Application.OpenForms[0].Control.Invoke(delegate{
for6 = new Form6();
for6.Show();
});
}

ProgressBar while finding a file

Hi I am trying to show a progress bar while in background the code is looping till it finds a file with specific name.
I have written following code for that but the progress bar values doesn't change.
What should I change in the code below?
public partial class Form1 : Form
{
BackgroundWorker backgroundWorker1 = new BackgroundWorker();
public Form1()
{
InitializeComponent();
progressBar1.Visible = false;
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork +=
new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.ProgressChanged +=
new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(backgroundWorker1_WorkDone);
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
progressBar1.Visible = true;
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// Your background task goes here
for (int i = 0; i <= 100; i++)
{
// Report progress to 'UI' thread
backgroundWorker1.ReportProgress(i);
// Simulate long task
while (!File.Exists(#"C:\Users\Test.txt"))
{
continue;
}
}
}
void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
// The progress percentage is a property of e
progressBar1.Value = e.ProgressPercentage;
}
void backgroundWorker1_WorkDone(object sender,
RunWorkerCompletedEventArgs e)
{
progressBar1.Visible = false;
}
}
The continue in your code will simply continue to the next iteration of the while(true) loop. It won't go back up to the for loop as you expect - it just keeps looping in there over and over again. If it wasn't a background worker, it'd hang your entire program. Since it is, it just hangs that thread. I expect that one CPU core stays at 100% while this is running.
That being said, while the goal here is admirable, there's no good way to accomplish it. Even if you fix the infinite loop, your progress bar will either "finish" at a low percentage (1%, 2%, 3%, done) or go up to 100, then stop updating, but without the file yet existing.

Using a Progress bar on Form Load

I am trying to Design a WinForms control in C# which will get some data from a database while it's loading.
I want to use a progress bar to show the progress.
I tried this code (and also many others):
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.Show();
progressBar1.Value = 10;
int n;
n = 50;//number of records in DB ,
double progress = 0;
double progstep = 25 / n;
for (int i = 1; i <= n; i++)
{
//getting
if (progress <= 100)
progressBar1.Value = (int)progress;
}
progressBar1.Value = 35;
n = 100;//number of records in DB for another data reading from DB ,
progress = 35;
progstep = 65 / n;
for (int i = 1; i <= n; i++)
{
//getting data from DB
dataGridView1.Rows.Add(....);
//Adding that data to a datagrid -- parametrs removed.
progress += progress;
if (progress <= 100)
progressBar1.Value = (int)progress;
}
}
But, the problem is that the form will wait until data reading progress is completed, and I can see just a full progress bar and all data loaded.
What should I do to fix this?
Since this is winforms, i'd recommend using a BackgroundWorker.
Basic example:
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.ProgressChanged += new DoWorkEventHandler(bgWorker_ProgressChanged);
bgWorker.RunWorkerAsync(//pass in object to process)
Which would then kickoff:
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
//Do all of your work here
bgWorker.ReportProgress(); //percent done calculation
}
Then the Progress changed event would fire to update the UI safely:
private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
Add a backgroundWorker1 to your form.
Then add a YourForm_Shown event
private void YourForm_Shown(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
Add on form's constructor after InitializeComponent()
backgroundWorker1.WorkerReportsProgress = true;
// This event will be raised on the worker thread when the worker starts.
backgroundWorker1.DoWork += new
DoWorkEventHandler(backgroundWorker1_DoWork);
// This event will be raised when we call ReportProgress.
backgroundWorker1.ProgressChanged += new
ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
And last add the voids of backgroundWorker1:
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// The progress percentage is a property of e
progressBar1.Value = e.ProgressPercentage;
}
And:
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= n; i++)
{
//getting data from DB.
dataGridView1.Rows.Add(....);
//Adding that data to a datagrid -- parametrs removed.
backgroundWorker1.ReportProgress(i);
// Simulate long task
}
}
This is simple mockup to show you how to work with background worker:
First in your OnLoad create background worker and attach 2 events to it:
var bw = new BackgroundWorker();
bw.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(WorkCompleted);
bw.DoWork += new DoWorkEventHandler(DoWork);
bw.RunWorkerAsync(data); // Assume data is list of numbers.
private void WorkCompleted(object sender, RunWorkerCompletedEventArgs e)
// After work completed remove event handlers and dispose.
{
var bw = (BackgroundWorker)sender;
bw.RunWorkerCompleted -= WorkCompleted;
bw.DoWork -= DoWork; bw.Dispose();
}
private void DoWork(object sender, DoWorkEventArgs e)
{
var data = (List<int>)e.Argument;
foreach (var number in data)
{
if (progressBar1.InvokeRequired)
{
progressBar1.Invoke((MethodInvoker)delegate
{ this.ProcessNumber(number); });
}
else
{
ProcessNumber(number);
}
}
}
private void ProcessNumber(int i)
{
progressBar1.PerformStep();
//do something with i
}
Take a look at BackgroundWorker control. During form load invoke;
backgroundWorker.RunWorkerAsync();
and override event DoWork to do the dirty work (load data from database) and ProgressChanged to update progress bar. In the event body (lets say the event signature will be something like this):
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
var worker = (BackgroundWorker)sender;
// time consuming operation
worker.ReportProgress(10, null);
// ... another stuff
}
private void backgroundWorker_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}

Categories

Resources