Why my background worker does not work for progress bar (By default set visibility to false .).
I am trying to have a progress bar in the background. when the user clicks OK button then I start the timer and make the progress bar visible.
and run backgroundWorker.RunWorkerAsync(); and in backgroundWorker_RunWorkerCompleted i set visibility of progress bar to false.
The problem is it just shows the progressbar but do not show the progress.
My code is here :
private void btnOk_Click(object sender, EventArgs e)
{
timer.Start();
progressBar.Visible = true;
backgroundWorker.RunWorkerAsync();
doSomeWork();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
timer.Stop();
progressBar.Visible = false;
}
private void timer_Tick(object sender, EventArgs e)
{
MessageBox.Show("called");
if (progressBar.Value == progressBar.Maximum)
{
progressBar.Value = progressBar.Minimum;
return;
}
progressBar.PerformStep();
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
Why does it not show progress in the progress bar ? Does whats wrong in it ?
Your backgroundWorker_DoWork is not doing anything. Move doSomeWork in DoWork event. And you need to set ReportProgress to true.
private void btnOk_Click(object sender, EventArgs e)
{
timer.Start();
progressBar.Visible = true;
backgroundWorker.ReportsProgress = true;
backgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
doSomeWork();
}
private void doSomeWork()
{
//do what you want here..
backgroundWorker.ReportProgress(yourprogresspercentagenumber);
//do what you want again..
backgroundWorker.ReportProgress(yourprogresspercentagenumber);
}
You are mixing two concepts here. Please decide if you want to use a timer or a background worker.
The reason why nothing happens is that your backgroundWorker_DoWork does nothing. So the background worker is immediatly finished and backgroundWorker_RunWorkerCompleted is called, stopping your timer again.
backgroundWorker_ProgressChanged is never called, because that event is only raised if you call backgroundWorker.ReportProgress() (and have backgroundWorker.ReportsProgress set to true).
I think the work you do in doSomeWork() should be done in backgroundWorker_DoWork while reporting progress. Try somthing like this:
private void btnOk_Click(object sender, EventArgs e)
{
progressBar.Visible = true;
backgroundWorker.ReportsProgress = true;
backgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
doALittleWork();
backgroundWorker.ReportProgress(10, null);
doMoreWork();
backgroundWorker.ReportProgress(20, null);
//...
doLastWork();
backgroundWorker.ReportProgress(100, null);
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressBar.Visible = false;
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
This should do what you want. The timer is not needed in that scenario.
Related
private void Form1_Load(object sender, EventArgs e)
{
webbrowser.Navigate(url);
}
private async void buttonDownload_Click(object sender, EventArgs e)
{
await Task.Run(()=> {
MessageBox.Show(webBrowser.Document.GetElementsByTagName("body")[0].InnerHtml);
});
}
The error displayed "The specified conversion is not valid" i read about it and it something because is another thread not ui thread, do you know a simple and short way to make this work ?
Edit
You must subscribe to webBrowser.DocumentCompleted event
webBrowser.DocumentCompleted += completed;
private void completed(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (sender is WebBrowser w)
{
var a = w.Document.GetElementsByTagName("body")[0].InnerHtml;
}
}
private async void buttonDownload_Click(object sender, EventArgs e){
webBrowser.Navigate(url);
}
I would rewrite your download method like this (I assume the webBrowser object is doing some 'long' computation and you don't want to block the UI thread)
private async void buttonDownload_Click(object sender, EventArgs e)
{
var htmlString = await Task.Run(()=> {
return webBrowser.Document.GetElementsByTagName("body")[0].InnerHtml;
});
MessageBox.Show(htmlString);
}
Also, are you sure that is the correct error? perhaps you overlooked some inner exception, which could explain more
I want to know the the task status runnning in A button event from the other button click.
Like this.
private void button1_Click(object sender, EventArgs e)
{
Task.Run(()=>{
//The method to take long time
//For example
Thread.Sleep(5000)
;});
}
private coid button2_Click(object sender, EventArgs e)
{
//until 5000ms
//the method to know the above task status (Runnning....)
//after 5000ms
//the method to know the above task status (Conpleted....)
}
It's not entirely clear what you're trying to achieve, but if you want to check the status of the task, you can get its reference when calling Task.Run()
private Task _task;
private void button1_Click(object sender, EventArgs e)
{
_task = Task.Run(() => Thread.Sleep(5000));
}
private void button2_Click(object sender, EventArgs e)
{
if (_task?.Status == TaskStatus.RanToCompletion)
//do something
}
The answer is as vague as the question, so if you could give me a bit more details, I could come up with a better more tailored answer.
Again, it's very unclear what you're looking for here...but this is an expanded version of Faylit's example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Task T = null;
private void Form1_Load(object sender, EventArgs e)
{
updateStatus();
}
private async void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
await (T = Task.Run(() =>
{
updateStatus();
System.Threading.Thread.Sleep(5000);
}));
button1.Enabled = true;
updateStatus();
}
private void button2_Click(object sender, EventArgs e)
{
updateStatus();
}
private void updateStatus()
{
if (label1.InvokeRequired)
{
label1.Invoke((MethodInvoker)delegate
{
updateStatus();
});
}
else
{
if (T == null)
{
label1.Text = "Task not started.";
}
else if (!T.IsCompleted)
{
label1.Text = "Task running...";
}
else
{
label1.Text = "Task completed.";
}
}
}
}
It might give you some more ideas.
On .NET Windows form, I have Background worker component that works fine. I have 5 forms, that has basically same Background worker on it with same code.
Can I extract this code to other class and somehow use it, considering this is an event? This is code I have on form. It takes 20 lines of code, and it would be nice if this can be refactored. Note: as you can see, I have already put it to other class BackgroundWorkerHelper, but can I also somehow refactor this events on Background worker, so that it is in other class as well, this way code is less and reused.
private void RunBackgroundWorker(string infoLabelText, int imageIndex)
{
BackgroundWorkerHelper.Run(backgroundWorker, progressBar, infoLabelText, imageIndex);
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorkerHelper.DoWork(backgroundWorker);
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
BackgroundWorkerHelper.ProgressChanged(sender, e, progressBar);
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
BackgroundWorkerHelper.RunWorkerCompleted(sender, e, progressBar);
}
Note: for now I would like to avoid using user control. I know I could do it, but then you have code that handles placing user control and so on. I am still not very good in it.
Here is solution, thanks to rory who gave me idea how to do it. First, I made this class:
public class BackgroundWorkerHelper
{
private static string _infoLabelText = string.Empty;
public BackgroundWorker _BackgroundWorker;
private BarEditItem _marqueeInfo;//this is marquee progress bar
public BackgroundWorkerHelper(BarEditItem marqueeInfo)
{
_marqueeInfo = marqueeInfo;
_BackgroundWorker = new BackgroundWorker();
_BackgroundWorker.WorkerReportsProgress = true;
_BackgroundWorker.WorkerSupportsCancellation = true;
_BackgroundWorker.DoWork += backgroundWorker_DoWork;
_BackgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
_BackgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
}
public void Run(string labelText, int imageIndex)
{
_marqueeInfo.Caption = labelText;
_marqueeInfo.ImageIndex = imageIndex;
if (!_BackgroundWorker.IsBusy)
_BackgroundWorker.RunWorkerAsync();
else
_marqueeInfo.Caption = "Busy processing saving data, please wait...";
}
public void DoWork()
{
for (int i = 0; i <= 5; i++)
{
_BackgroundWorker.ReportProgress(i); // call backgroundWorker_ProgressChanged event and pass i (which is e argument e.ProgressPercentage) to update UI controls
Thread.Sleep(250);
}
}
public void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
_marqueeInfo.Visibility = BarItemVisibility.Always;
}
public void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_marqueeInfo.Visibility = BarItemVisibility.Never;
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
DoWork();
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ProgressChanged(sender, e);
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
RunWorkerCompleted(sender, e);
}
then in FORM, in class level above constructor place
private readonly BackgroundWorkerHelper _backgroundWorkerHelper;
then in Form Constructor instantiate class
_backgroundWorkerHelper = new BackgroundWorkerHelper(marqueeInfo);
and then I just call it in my form
_backgroundWorkerHelper.Run("Saving", 14);
I am attempting to use a Backgroundworker to keep my Main UI thread open and not freezing up. I am stepping thro my code and have set a breakpoint on both the backgroundWorker1.RunWorkerAsync(); which once hits just leaves the method and on the foreach line -> which is never hit.
What is the proper way to use a Backgroundworker?
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
}
private void btnQuery_Click(object sender, EventArgs e)
{
grid1.Rows.Clear();
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
foreach (string name in studentRoster)
{
InsertIntoDB();
}
}
Here is your code with the handlers added and some comments.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.DoWork += new DoWorkEventHandler(BackgroundWorker_DoWork);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(BackgroundWorker_ProgressChanged);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorker_RunWorkerCompleted);
}
private void btnQuery_Click(object sender, EventArgs e)
{
grid1.Rows.Clear();
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
foreach (string name in studentRoster)
{
InsertIntoDB();
// You can report progress by calling the following function.
//backgroundWorker1.ReportProgress(int percentProgress, object userState)
// You can set the percentProgress to any valid integer value,
// and userState can be any object you want.
// You can also check to see if this operation has been sent a request to cancel.
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
return;
}
}
// You can send information back to the main thread by setting e.Result to any object you want.
}
private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Do something with the event that is being raised.
// To pass a value back through to this event, use the percentProgress and userState
// parameters of the ReportProgress function.
// the userState object that you pass will be received here as e.UserState
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// This event is raised by the background worker when the DoWork method is completed.
// You can receive information back from the worker thread by evaluating e.Result
}
}
}
I tried to implement progressbar in windows form but progress bar is showing result after completion of whole execution.
public Status()
{
InitializeComponent();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (ForReporting.FileProcessed <= ForReporting.TotalNumberFiles)
{
Thread.Sleep(100);
int temp=ForReporting.FileProcessed*100;
temp = temp / ForReporting.TotalNumberFiles;
backgroundWorker1.ReportProgress(temp);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void Status_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}