I have a Backgroundworker and I want to display a loading gif till the worker has finished.
My problem is that I cannot use
while(worker.IsBusy)
Thread.Sleep(50);
because that blocks the UI Thread and my GIF from updating it's frames.
Same problem occurs when using an AutoResetEvent and myAutoResetEvent.WaitOne();
Do you have any idea how to wait for the Backgroundworker to finish and still be able to display a GIF?
The whole point of the BackgroundWorker is to allow the UI to continue running.
And, you specifically want a GIF to continue to update with the BackgroundWorker is running.
So it's a perfect solution.
Clearly, though, you want the UI to be "non-iteractive" while the BackgroundWorker is running. Well, there's a fairly basic way to do that.
Here it is:
private void SaveButton_Click(object sender, EventArgs e)
{
SaveButton.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(5000);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
SaveButton.Enabled = true;
}
Basically, you just disable the controls that you don't want to user to interact with and re-enable them when the BackgroundWorker is done.
Related
I implemented a windows form in c# with a progress bar in marquee style and a backgroudworker to do a job. The progress bar animation is working correctly when the backgroundworker sleeps, but it hangs when the backgroundworker starts to do something. Does anyone know what I am doing wrong?
Thanks in advance for your answers.
Here is my code:
public FormProgressBarMarquee()
{
InitializeComponent();
this.progressBar1.Style = ProgressBarStyle.Marquee;
this.progressBar1.MarqueeAnimationSpeed = 50;
Shown += new EventHandler(FormProgressBar_Shown);
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_Completed);
}
void FormProgressBar_Shown(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(10000);
// the progress bar animation works correctly
longtimerunningprocess.start();
// the progress bar animation stops
}
void backgroundWorker1_Completed(object sender, RunWorkerCompletedEventArgs e)
{
Debug.Print(" :: FormProgressBar :: ...Pack And Go loaded, close form...");
this.DialogResult = DialogResult.OK;
this.Close();
}
I could finally solve the problem myself. Thanks anyway for the comment #digvijay which put me on the right track.
The program I am writing is part of a class library. longtimerunningprocess is part of the main program and is executed in the main UI thread.
Although I always try to keep the splash screen in the main UI thread and put the non UI work into a separate thread using a backgroundworker, this time I had to put the splash screen in a separate thread.
To do so, I used this suggestion:
https://stackoverflow.com/a/48946
I am writing a Kiosk-type program for a media center PC. I have some pictureBoxes as my buttons, and would like a label or another pictureBox (acting as a label) to be visible/not visible and be triggered by a MouseEnter and MouseLeave event.
When the MouseLeave event happens(triggering Visible=false), a white box appears in place of the pictureBox or label that was previously there for a split second until the background image fills back in.
I have read up a little bit on using the BackgroundWorker to "pre-load" my pictureBox or labels. I am not sure that i am doing it right. I am very new to programming; i dabble here and there, and do not have any formal training in c#.
I am not looking for anyone to write the code for me, but i also am not objected to that either. A simple example of how to use it should suffice.
I have a background image (1920x1080) on my form. I think this image is actually having a harder time refreshing after the label or pictureBox's visibility is set to false.
private void pictureBox1_MouseEnter(object sender, EventArgs e)
{
this.pictureBox9.Visible = true;
}
private void pictureBox1_MouseLeave(object sender, EventArgs e)
{
this.pictureBox9.Visible = false;
}
I am attempting to use the backgroundWorker DoWork event, but really have no idea what i am doing.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
this.pictureBox9.Visible = true;
this.pictureBox9.Visible = false;
}
My question is, "How do i use backgroundworker to effectively reduce the lag caused by changing visibilty of my pictureBoxes or lables?
The BackgroundWorker works like this:
BackgroundWorker workerOne = new BackgroundWorker();
BackgroundWorker workerTwo = new BackgroundWorker();
private void MyForm_Load(object sender, EventArgs e)
{
workerOne.DoWork += workerOne_DoWork;
workerTwo.DoWork += workerTwo_DoWork;
}
private void ThingOne_Click(object sender, EventArgs e)
{
workerOne.RunWorkerAsync();
}
private void ThingOne_Click(object sender, EventArgs e)
{
workerTwo.RunWorkerAsync();
}
void workerOne_DoWork(object sender, DoWorkEventArgs e)
{
//This will run as async and not interupt main thread
}
void workerTwo_DoWork(object sender, DoWorkEventArgs e)
{
//This will run as async and not interupt main thread
}
I've included two in the example. Basically the RunWorkerAsync breaks it off in its own thread.
I do not recommend using BackgroundWorker for this because the fact of changing the Visibility of a Visual Element requires the Main Thread and not a Worker Thread. What I recommend in any case is to handle the Opacity so you don't have to load the image again.
I'm writing a project in C# and I've run into a problem using backgroundworker to keep my form responsive whilst an expensive process runs. When I use the bgw method, I get an OutOfMemory exception. However, if I just run my ExpensiveMethod() directly without using bgw then I don't have any issues. Any ideas? I really want to be able to implement a progress bar whilst this method runs (its quite a time consuming process and the user needs to know how long is left). I am fairly new to C# and definitely a novice with threading.
Here is how I'm implementing my bgw and ExpensiveMethod():
private void btnGo_Click(object sender, EventArgs e)
{
myProgressBar.Visible = true;
bgw.RunWorkerAsync();
}
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
ExpensiveMethod();
}
private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
myProgressBar.Value = e.ProgressPercentage;
}
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
myProgressBar.Visible = false;
}
private void ExpensiveMethod()
{
// do a big calculation and call this every so often:
bgw.ReportProgress((int)percentComplete);
}
This method, however, works fine with no memory exceptions, but obviously locks up the form whilst it runs:
private void btnGoThatWorks_Click(object sender, EventArgs e)
{
ExpensiveMethod();
}
Any ideas? I am on Windows7 32-bit.
It appears that the answer was that I was calling bgw.ReportProgress((int)percentComplete); far too often --- changing the code so it only reports every few percent seems to have fixed the issue.
I am writing a sudoku solver app. The calculation time of the solver in certain cases can exceed 3 seconds, which would require a progress bar.
so my code:
private void solveButton_Click(object sender, RoutedEventArgs e)
{
progressBar1.Visibility = Visibility.Visible;
progressBar1.IsIndeterminate = true;
mySolver.Solve(initialValue)
progressBar1.Visilibity=Visilibity.collapsed;
progressBar1.IsIndeterminate = false;
}
The code here is a condensed version of my actual code. This code doesn't work, as the progress bar does not appear at all. It seems to me that the UI updates only after event is finised executed. If I didn't hide the progressbar after the solver step, the progressBar appears after the sudoku is solved. Replacing the solver with thread.sleep(1000) also results in the same UI update.
thanks for your help.
You should start the solver on a separate thread. That way the user interface thread can keep working on user interface objects even during the solving process, which allows your progress bar to be drawn on the screen and updated.
Problem is that your UI thread is not getting free in between to display the progress bar
You need to use the background worker to solve the problem and in the main UI thread you should display the progress bar
private void solveButton_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += new DoWorkEventHandler(DoWork);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);
bg.RunWorkerAsync();
progressBar1.Visibility = Visibility.Visible;
progressBar1.IsIndeterminate = true;
}
void DoWork(Object sender, DoWorkEventArgs args)
{
mySolver.Solve(initialValue)
}
void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs args)
{
// this method will be called once background worker has completed it's task
progressBar1.Visilibity=Visilibity.collapsed;
progressBar1.IsIndeterminate = false
}
Technically the code works fine, you just wrote the wrong code.
Your solver is running on the UI thread so it never has a chance to draw the progress bar before you hide it again. You need to spawn a thread (or use a background worker) to free up the UI thread so it can draw your progress bar.
I don't know too much about WP7 but with winforms if you have a long running function it needs to be run on a different thread than the UI.
Is BackgroundWorker available to you on WP7? you can update the bar on the ProgressChanged event and change the viability on the RunWorkerCompleted event
private void solveButton_Click(object sender, RoutedEventArgs e)
{
progressBar1.Visibility = Visibility.Visible;
progressBar1.IsIndeterminate = true;
solveButton.Enabled = false; //I reccomend this so the button can't be pressed twice.
BackgroundWoker bw = new BackgroundWorker();
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
bw.DoWork += bw_DoWork;
bw.ProgressChanged += bw_ProgressChanged;
bw.RunWorkerAsync()
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
mySolver.Solve(initialValue, e)
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Error != null)
{
//Handle any exceptions that happened in the background worker.
}
progressBar1.Visilibity=Visilibity.collapsed;
progressBar1.IsIndeterminate = false;
solveButton.Enabled = true;
((IDisposable)sender).Dispose();
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
//inside mySolver
void Solve(somthing initialValue, DoWorkEventArgs e)
{
//Your solver work
e.ReportProgress(progress); //a int from 0-100
//more solver work
}
If you still want to run it on the UI Thread (which i wouldn't recommend!!) you can use the progressbar from the WP7 Toolkit that was released yesterday. It contains a progressbar that will work while your UI Thread is blocked.
I want to print a html page from c# application but on a back ground thread because if I print the doc on main thread UI freezes for few seconds and I dont want that.
I have tried WebBrowser control but it need to be hosted on some form to get it work. Hosting this control is still acceptable but Print method needs to be called from same thread the control was created on. I tried calling Print method of WebBrowser from other thread but it neither work nor it give any error/exception. I have also tried InternetExplorerClass but it start iexplorer.exe and takes too much time.
Is there any other way in which I can print html page on a diffrent (non UI) thread?
I'd use a backgroundworker for this purpose - since you've already got a winform and everthing.
Drag a background worker and a webbrowser to your form and you can use the following code (UI freezes for milliseconds when the print is actually spooled);
I've used a test button (2) for the call;
using System.Threading;
private void button2_Click(object sender, EventArgs e)
{
if (!this.backgroundWorker1.IsBusy)
{
this.backgroundWorker1.RunWorkerAsync("http://www.stackoverflow.com/");
}
else
{
MessageBox.Show("Already working on that piece of paper!");
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
this.webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
this.webBrowser1.Navigate((string)e.Argument);
//-- only when you need to read very bulky pages: Thread.Sleep(1000);
e.Result = true;
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
this.webBrowser1.Print();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.webBrowser1.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
}
Does something like this not work?
webBrowser1.BeginInvoke((MethodInvoker)delegate{webBrowser1.Print();});