I would like to add progress bar to my "app".
ProgressForm progressForm = new ProgressForm();
progressForm.paths.path1= pathSource1;
progressForm.paths.path2 = pathSource2;
progressForm.paths.path3= pathSource3;
progressForm.paths.path4=path4;
progressForm.paths.path5 = path5;
progressForm.ShowDialog();
During load event of progress form backgroundworker is fired.
private void ProgressForm_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//some code
backgroundWorker1.ReportProgress(1, "Loading Data From File");
//some code
backgroundWorker1.ReportProgress(0, "Loading Data From ...File");
//some code
backgroundWorker1.ReportProgress(10, "Loading Data From... File 2");
//some code
backgroundWorker1.ReportProgress(0, "hjhgjhgjfhgh");
for (int i = 0; i < dataCollection.Count(); i++)
{
//some code
backgroundWorker1.ReportProgress(((i+1) / data1.Count())*100, "");
//some code
}
}
WorkerReportsProgress is set to true, unfortunatelly ReportProgress method is not firing event ProgressChange (I set breakpoint there)
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage!=0)
{
progressBar.Value = e.ProgressPercentage;
}
if (e.UserState.ToString()!="")
{
lblProgressDesc.Text = e.UserState.ToString();
}
}
What could be a cause of that ?
You should set the WorkerReportsProgress property to true
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker_properties(v=vs.110).aspx
The following code example demonstrates the use of the ProgressChanged event to report the progress of an asynchronous operation to the user. This code example is part of a larger example provided for the BackgroundWorker class.
// This event handler updates the progress bar.
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
}
I had a similar issue, where the ProgressChanged and RunWorkerCompleted events weren't firing. I was starting the RunWorkerAsync process from the UI thread and then sitting in a sleep loop waiting for the IsBusy flag to change. Turned out I needed to add an Application.DoEvents to the loop in order for the events to fire.
Ok, I am sorry, I found the reason. I do not why but VS did not treat mentioned method/event handler as an event of backgroundworker. I went to properties -> events -> clicked twice on ProgressChanged and it added new event handler: backgroundWorker1_ProgressChanged_1
Related
I am confused about the BackGroundWorker RunWorkerCompleted event execution timing.
This is my test code
private string hellow="hello";
private void button1_Click(object sender, EventArgs e)
{
bool createAndRunWorkResult = CreateAndRunWork();
if (createAndRunWorkResult)
{
//Do something that need wait RunBackGroundWorkerCompleted execute here.
//MessageBox.Show(hello);
}
}
private bool CreateAndRunWork()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync();
return true;
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
//Nothing here;
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
hello="aloha";
}
My design workflow is to click the button1 and then do something after RunWorkerCompleted has executed.
But RunWorkerCompleted seems to be located on the bottom of the method stack. In other words: I'm getting createAndRunWorkResult before RunWorkerCompleted executes. What confuses me is if I uncomment MessageBox.Show(hello) in button1_Click, the MessageBox.Show(hello) will wait until worker_RunWorkerCompleted has executed. But, I still get a "hello" messagebox rather than "aloha".
I guess all UI operation will be located below the RunWorkerCompleted at the method stack.
However, I'm not sure if my assumption is correct and if there is a way to force do something only after RunWorkerCompleted has been executed?
The Problem is, that a backgroudnworker is another thread that you can't wait for.
The backgroundworker is telling you when it's finished its work.
so your code should look like this
private string hellow="hello";
private void button1_Click(object sender, EventArgs e)
{
bool createAndRunWorkResult = CreateAndRunWork();
}
private bool CreateAndRunWork()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync();
return true;
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
//Nothing here;
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
hellow="aloha";
//Do something that need wait RunBackGroundWorkerCompleted execute here.
//MessageBox.Show(hellow);
}
I recommend reading this: http://msdn.microsoft.com/en-us/library/ms173178%28v=vs.120%29.aspx
about threading
BackgroundWorker object is designed to simply run a function on a different thread and then call an event on your UI thread when it's complete, So in your code you should call function which you want to run after RunWorkerCompleted.
There are 3 Steps:
Create a BackgroundWorker object.
Tell the BackgroundWorker object what task to run on the background thread (the DoWork function).
Tell it what function to run on the UI thread when the work is complete (the RunWorkerCompleted function).
If you write function call in your code
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Test();//This is the code which in your case you want to run
}
void Test()
{
hello = "Hola";
MessageBox.Show(hello);
}
you will get HOLA message this is due to step 3 mentioned above. Hope this helps
I am working on a program which uses a backgroundWorker to append text to a Textbox control. My problem is that simply, the backgroundWorker will not insert text into the Textbox control, it just remains blank.
My code:
private void button1_Click(object sender, EventArgs e) {
backgroundWorker1.RunWorkerAsync(); //Start the worker
}
public void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
this.writeText("Hello World!");
}
public void writeText(string text) {
textbox1.Text = textbox1.Text + text + "\r\n";
textbox1.SelectionStart = textbox1.Text.Length;
textbox1.ScrollToCaret(); //Scroll to the end of the textbox
}
Looking at the code, it seems fine (to me anyway) and it compiles fine too, so it's probably something very obvious that I am missing.
If someone would care to enlighten me on what I am doing wrong, it would be much appreciated ;)
In the method subscribed to the DoWork event, do your long-running operation. Then, within the worker method, you can call ReportProgress to send updates. This causes the OnProgressChanged event to fire on your UI thread, at which time you can make changes to your UI.
Alternately, if you're on .NET 4.5, you could use the async/await pattern to keep your UI responsive while performing long-running, I/O-bound operations. For CPU-bound operations, a BackgroundWorker is still appropriate.
As always, MSDN is a fantastic resource. From the BackgroundWorker page:
To set up for a background operation, add an event handler for the
DoWork event. Call your time-consuming operation in this event
handler. To start the operation, call RunWorkerAsync. To receive
notifications of progress updates, handle the ProgressChanged event.
To receive a notification when the operation is completed, handle the
RunWorkerCompleted event.
You must be careful not to manipulate any user-interface objects in
your DoWork event handler. Instead, communicate to the user interface
through the ProgressChanged and RunWorkerCompleted events.
You can declare a delegate at the class level for your Form.
public delegate void WriteLogEntryDelegate(string log_entry);
You can then wrap up most of the logic in another method:
void WriteLogEntryCB(string log_entry)
{
if (textbox1.InvokeRequired == true)
{
var d = new WriteLogEntryDelegate(WriteLogEntryCB);
this.Invoke(d, log_entry);
}
else
{
textbox1.Text(log_entry + "\r\n");
this.textbox1.SelectionStart = this.textbox1.Text.Length;
this.textbox1.ScrollToCaret();
}
}
You can then call that Function from your DoWork Method:
public void DoWork(object sender, DoWorkEventArgs e)
{
WriteLogEntryCB("Hello World!");
}
Edit to Include Daniel Mann's Suggestion:
Another way would be to cast the sender in the DoWork method as the BackgroundWorker, and then call the ReportProgress Method (or use the RunWorkerCompleted Event Handler).
void bw1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
worker.ReportProgress((1));
}
You would then require an event handler for the ProgressChanged Event:
void bw1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//update textbox here
}
Finally, you could also use the RunWorkerCompleted Event Handler:
void bw1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//update textbox here
}
In the writeText method, the UI related code should be invoked by the UI
thread that create the UI controls.
What you do is called attempt to get access to the UI element from other the thread rather than the thread where element was created.
Read more info here.
I need to be able to continuously run my BackgroundWorker. The DoWork event contains a pool threaded process and the OnComplete updates my UI.
I have not been able to find a way to infinitely loop the BackgroundWorker.RunWorkerAsync() method without the whole program freezing. Any help would be greatly appreciated.
You have to make a loop in your DoWork-Method. To update your UI you shoud use the ProgressChanged-Method. Here is a small example how this can look like
public Test()
{
this.InitializeComponent();
BackgroundWorker backgroundWorker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
backgroundWorker.DoWork += BackgroundWorkerOnDoWork;
backgroundWorker.ProgressChanged += BackgroundWorkerOnProgressChanged;
}
private void BackgroundWorkerOnProgressChanged(object sender, ProgressChangedEventArgs e)
{
object userObject = e.UserState;
int percentage = e.ProgressPercentage;
}
private void BackgroundWorkerOnDoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker) sender;
while (!worker.CancellationPending)
{
//Do your stuff here
worker.ReportProgress(0, "AN OBJECT TO PASS TO THE UI-THREAD");
}
}
I have done this in the past when needing something to run in the background.
If you try to run the backgroundworker while it is running, you will get an excpetion!
That is why i make the BackGroundWorker start itself when it is done in the completed event.
And then it will loop forever.
private void Main_Load(object sender, EventArgs e)
{
// Start Background Worker on load
bgWorker.RunWorkerAsync();
}
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(1000); // If you need to make a pause between runs
// Do work here
}
private void bgCheck_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Update UI
// Run again
bgWorker.RunWorkerAsync(); // This will make the BgWorker run again, and never runs before it is completed.
}
timer.interval=60000 // 1 min
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
try
{
//Do something
}
catch
{
}
}
on backgroundworker completed event, just start background worker again
If your program is freezing, it may be because your infinitely looping background worker thread is spinning, using 100% CPU. You haven't said why you need it to run in an infinite loop, but you could start by putting a Thread.Sleep in that loop.
I have a MainWindow with eventhandler which is not working properly. I have made simple model of this problem. Please see comment in code where the problem is:
public partial class MainWindow : Window
{
public event EventHandler Event1;
public MainWindow()
{
Event1 += MainWindow_Event1;
InitializeComponent();
}
void MainWindow_Event1(object sender, EventArgs e)
{
textBox1.Text = "wth!?"; //Not changing text box. Not showing message. If delete this line, it will work fine
MessageBox.Show("raised");
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
EventHandler evt = Event1;
while (true)
{
Thread.Sleep(500);
evt(null, null);
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += bw_DoWork;
bw.RunWorkerAsync();
}
}
Please explain this behavior and how can I fix it?
The problem is that you're invoking the event from a background thread. This will not work and the program is simply hanging when trying to access the TextBox. However, if you change this code:
textBox1.Text = "wth!?"; //Not changing text box. Not showing message. If delete this line, it will work fine
MessageBox.Show("raised");
to this:
this.Dispatcher.BeginInvoke((Action)delegate()
{
textBox1.Text = "wth!?"; //Not changing text box. Not showing message. If delete this line, it will work fine
MessageBox.Show("raised");
});
it'll work for you.
You can't update the UI elements from the background thread.
The worker thread fails by exception trying to access the UI element (Text property). So messageBox isn't showing as well. Use notification mechanisms, or Dispatcher calls (there is a wast amount of information like this on the web)
Here are possible duplicates/help:
Update GUI using BackgroundWorker
Update GUI from background worker or event
This problem is because you need to use the Synchronization Context of the current Thread for comunicating between threads, some thing like this
private void Button_Click(object sender, RoutedEventArgs e)
{
var sync = SynchronizationContext.Current;
BackgroundWorker w = new BackgroundWorker();
w.DoWork+=(_, __)=>
{
//Do some delayed thing, that doesn't update the view
sync.Post(p => { /*Do things that update the view*/}, null);
};
w.RunWorkerAsync();
}
Please check this question, hope can helps...
Lets say I have Task 1:
private void Task1()
{
//Here is some Code, could be any "longer" Task -
//For Example: Grab all words from a .txt File and fill in a List<String>
}
Then I have an other Task 2:
private void Task2(string word)
{
//So lets say theres a Label on my WinForm..
//Now While Task1 is grabbing the words, Task2 should fill a Label
//with the added 'word' (parameter) - (Task2 will be called from Task1
}
Actually I don't know how to make this possible, or whats the best way. On the UI I should be able to see the Label.Text changing (every word).. So I need to make a second Thread? How could I do this? Maybe someone could help me, cheers
UPDATE:
I tried it now with the Backgroundworker, but something seems to be false.. its actually not working, nothing happens on the form
Code:
public void CreateAndSaveAMatch(DateTime date) //That method is being called several times
{
//HERE IS CODE, WHICH CREATES AND SAVES A MATCH
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync(date);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
backgroundWorker1.ReportProgress(0, Convert.ToDateTime(e.Argument).ToShortDateString());
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = (string)e.UserState; //here on the Label I would like to show the Date
}
Ok, try this. This is a simple example that will show you how to solve your problem using BackgroundWorker. Also note that there are many other solutions. To use this example create a Form in a new project that only has a button and a label. Also note that this is a supplement of the other answers which were correct.
public partial class Form1 : Form
{
BackgroundWorker createAndSaveAMatchBGW;
public Form1()
{
InitializeComponent();
createAndSaveAMatchBGW = new BackgroundWorker();
createAndSaveAMatchBGW.DoWork += new DoWorkEventHandler(createAndSaveAMatchBGW_DoWork);
createAndSaveAMatchBGW.ProgressChanged += new ProgressChangedEventHandler(createAndSaveAMatchBGW_ProgressChanged);
createAndSaveAMatchBGW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(createAndSaveAMatchBGW_RunWorkerCompleted);
createAndSaveAMatchBGW.WorkerReportsProgress = true;
}
private void button1_Click(object sender, EventArgs e)
{
createAndSaveAMatchBGW.RunWorkerAsync(DateTime.Now);
}
void createAndSaveAMatchBGW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("BackgroundWorker finished");
}
void createAndSaveAMatchBGW_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = ((DateTime)e.UserState).ToString("ss");
}
void createAndSaveAMatchBGW_DoWork(object sender, DoWorkEventArgs e)
{
//BackgroundWorker does something for a 10 seconds, each second it Reports
BackgroundWorker bgw = (BackgroundWorker)sender;
DateTime dt = (DateTime) e.Argument;
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1000);
dt = dt.AddSeconds(1);
bgw.ReportProgress(0, dt);
}
}
}
And if you report from CreateAndSave... method only once per its execution, then you can use this code:
BackgroundWorker createAndSaveAMatchBGW;
public Form1()
{
InitializeComponent();
createAndSaveAMatchBGW = new BackgroundWorker();
createAndSaveAMatchBGW.DoWork += new DoWorkEventHandler(createAndSaveAMatchBGW_DoWork);
createAndSaveAMatchBGW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(createAndSaveAMatchBGW_RunWorkerCompleted);
}
private void button1_Click(object sender, EventArgs e)
{
createAndSaveAMatchBGW.RunWorkerAsync(DateTime.Now);
}
void createAndSaveAMatchBGW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
label1.Text = ((DateTime)e.Result).ToString();
}
void createAndSaveAMatchBGW_DoWork(object sender, DoWorkEventArgs e)
{
DateTime dt = (DateTime) e.Argument;
//you do something with your DateTime
dt = dt.AddDays(10);
e.Result = dt;
}
Use BackgroundWorker for reporting progress from first task. Drag this component from toolbox to your form, and subscribe to DoWork and ProgressChanged events. Also set property WorkerReportsProgress to true. Then start you first task asynchronously:
// this will execute code in `DoWork` event handler
backgroundWorker1.RunWorkerAsync();
Next - use userState object to pass processed words:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// grab words in a loop and report progress
backgroundWorker1.ReportProgress(0, word);
}
And last step - update label in ProgressChanged event handler
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text += (string)e.UserState; // this is your grabbed word
}
The simplest way to achieve this kind of thing is using BackgroundWorker.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
BackgroundWorker automatically handles thread marshalling and provides events that allow you to update the UI. The event handlers run on the UI thread.
The things you do in Task1 could be moved into a BackgroundWorker, and the updates to the UI that you propose to do in Task2 can actually be in response to progress events from BackgroundWorker.
ProgressChangedEventArgs provides for user-defined data that could hold the current word.
However, Winforms (and indeed pretty much any UI) will not be able to keep up with a separate CPU thread just loading words from a file if you intend to show every word you load.
Task1 could be started on a separate thread.
You wouldn't actually need a Task2 unless there was some complex logic being performed to update the TextBox. You you really need to do is use TextBox.Invoke() to invoke the update on the UI Thread from Task1.