Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
the question might be seems to be a regular one, but it isn't.
No matter what am I doing, the progress bar just not increasing.
In the base concept I have a GUI form and it has got a bacgroundworker. In the backgroundworker I am using a self defined class to read out the data from a measurement file. I want to increase the progress bar when it is done with one file, but no matter what am I doig it does nothing.
I have read the documentation but nothing.
https://learn.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-set-the-value-displayed-by-the-windows-forms-progressbar-control?view=netframeworkdesktop-4.8
I have tried:
worker.ReportProgress method
Controls.Invoke((MethodInvoker)delegate{}); method
Furhtermore tried the Control.Update() and Control.Refress() too, but these are not working too.
Please help!
Thank you all in advance!
The reason the Progress bar won't update is that the UI cannot be updated from background threads. Backgroundworker runs on a background thread, which keeps the UI responsive.
Three solutions:
In the backgroundworker, start a new Task that runs on the Main UI thread, and update the progress bar there. This is bad coding, but there are other use cases where .InvokeRequired is valid.
Use backgroundworker ReportProgress. In the ProgressChanged handler (which runs on the UI thread), update the progressbar as normal.
Rewrite your app to use the "await Function1()/ async Task Fuction1() pattern instead of Backgroundworker. Here .InvokeRequired will likely be used. You can also use EventHandlers to return responses to the caller.
Examples Follow
#1 Warning bad coding style!
private void bgw1_DoWork(Object sender, DoWorkEventArgs e)
{
...
await Task.Run( () =>
{
progressBar1.InvokeIfRequired( o =>
{
progressBar1.Value += 1;
} );
});
...
}
public static class MyExtensions
{
public static void InvokeIfRequired<T>(this T obj, InvokeIfRequiredDelegate<T> action) where T : ISynchronizeInvoke
{
if (obj.InvokeRequired)
{
obj.Invoke(action, new Object[] { obj });
}
else
{
action(obj);
}
}
}
#2 This way works well:
private void bgw1_DoWork(Object sender, DoWorkEventArgs e)
{
...
worker.ReportProgress(0, 50); //50% progress out of 100
...
}
private void bgw1_ProgressChanged(Object sender, ProgressChangedEventArgs e)
{
if(e.UserState is Int32 i)
{
progressBar1.Value = i;
}
}
#3
Is a complete re-write and likely outside the scope of your question.
Remember to mark this as an answer if it helps you.
Related
This question already has answers here:
An async/await example that causes a deadlock
(5 answers)
Closed 4 years ago.
I know there are quite a lot of Post about Task deadlocks, but I simply can't find the right sollution.
So I basically have this setup:
public event EventHandler StateChangedEvent;
public bool Busy
{
...
set
{
...
this.StateChangedEvent?.Invoke(this, EventArgs.Empty)
}
}
public void Main()
{
...
this.StateChangedEvent += this.OnStateChangedEvent;
}
public void OnStateChangedEvent(object sender, EventArgs e)
{
this.TextBox.Invoke(() => this.TextBox.Text = "Change");
this.Invoke(() => this.Cursor = Cursors.WaitCursor);
}
public void ButtonAction_Click(object sender, EventArgs e) //actually part of an API with an virtal - override method on between. Can't change here to async
{
...
Task.Run(async () => await this.AsyncDoStuff()).Wait();
... // Synchron stuff needs to be done afterwards
}
public async Task AsyncDoStuff()
{
this.Busy = true; //Causes Deadlock
await Stuff1();
await Stuff2();
}
So in reality those calls are split among different classes, but the basic structure remains. Yes I know I should go async all the way up, but let's say the first ButtonAction_Click is part op an API/Framework and can't be changed to async.
I know the reason is because I block the UI Thread and then access it again...So what is the best solution for this?
Thanks in advance!
So from your other comments it sounds like the code in ButtonAction_Click is outside your control and you can't change it. Unfortunately, that's where the problem is - this event handler is totally blocking the UI thread until the work has finished. There's no way to unblock the thread.
Your only recourse is to avoid any blocking interactions with the UI thread.
The following code from your example is definitely going to cause deadlock, because Invoke() will block until the UI (which is already blocked) responds:
this.TextBox.Invoke(() => this.TextBox.Text = "Change");
this.Invoke(() => this.Cursor = Cursors.WaitCursor);
You could try using BeginInvoke() instead of Invoke(), but the unfortunate consequence is that these UI changes won't actually execute until the UI thread is unblocked, and by then your background work is already finished. It might fix your deadlock, though.
This question already has an answer here:
Control 'progressBar1' accessed from a thread other than the thread it was created on in my business class [duplicate]
(1 answer)
Closed 4 years ago.
I have a function with several loopings and database query, I want to call it asynchronously by passing a progress bar to show the user the progress.
When I call the thread the program hangs I can not even close
when I call synchContext.Post (state => etlBusiness.LoadData (progressBar), null); it freezes, it is not feasible to bring the logic of loadData to UI there are many methods being called the inside
public partial class Home : Form
{
public Home()
{
InitializeComponent();
synchronizationContext = System.Threading.SynchronizationContext.Current;
}
private SynchronizationContext synchronizationContext;
public SynchronizationContext context = SynchronizationContext.Current;
public Thread _myThread = null;
private void btnSend_Click(object sender, EventArgs e)
{
_myThread = new Thread(() => LoadData(synchronizationContext, progressBar1));
_myThread.Start();
}
private void LoadData(System.Threading.SynchronizationContext synchContext, ProgressBar progressBar)
{
string filePath = tbPath.Text;
ETLBusiness etlBusiness = new ETLBusiness(filePath);
synchContext.Post(state => etlBusiness.LoadData(progressBar), null);
_myThread.Abort();
}
}
You don't need to use Thread.Abort(), SynchronizationContext or even use "asynchronous" code (I assume you're referring to await/async which you cannot call unless your target API actually provides true async functionality, note that using Task.Run is not the same thing): WinForms has built-in functionality for running code in the UI thread in the Invoke/BeginInvoke methods.
For progress reporting, I don't recommend passing-around a ProgressBar as that's a brittle design and means your inner business logic has a dependency on WinForms which prevents you from using it in a WPF, ASP.NET or headless process; instead you could have a private method that updates the UI via a callback, like so:
private ProgressBar progressBar;
public Home()
{
this.InitializeComponent();
}
private void btnSend_Click( Object sender, EventArgs e )
{
Task.Run( (Action)this.LoadData )
}
private void UpdateProgress( Float progress )
{
if( this.InvokeRequired )
{
this.BeginInvoke( (Action<Float>)this.UpdateProgress, progress );
return;
}
this.progressBar.Value = progress * this.progressBar.Maximum;
}
private void LoadData()
{
ETLBusiness etlBusiness = new ETLBusiness(filePath);
etlBusiness.LoadData( this.UpdateProgress ); // You'll need to replace its progressBar parameter with a callback to `this.UpdateProgress`.
}
Where your ETLBusiness.LoadData method should be changed to this:
void LoadData( Action<Float> progressCallback );
me again. I posted a comment in your last post. The problem is coming from my solution. What is happening is you are creating and starting a thread, you then, with synchContext.Post() send the logic of ETLBusiness.LoadData() back to the main thread. What needs to happen is one of the two following options:
Move the logic of ETLBusiness.LoadData() into Form.LoadData() (the method called by the thread), and then use synchContext.Post(state => progressBar1.SetPercent()) to update the progressBar specifically.
Move the thread to the ETLBusiness class. and use synchContext.Post(state => progressBar1.SetPercent()) to update the progressBar specifically.
Sorry again, this problem came from my solution to your previous post
I am stuck on an issue where I am using Backgroundworker to show the progress of my work in a progress bar. Code used for backgroundworker:-
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(200);
for (int i = 0; i <= 100; i++)
{
Delegate del= new DELEGATE(simulateHeavyWork);
this.Invoke(del);
backgroundWorker1.ReportProgress(i);
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
backgroundWorker1.ReportProgress(0);
return;
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
percentLabel.Text = e.ProgressPercentage.ToString() + "%";
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("Cancelled");
}
else
{
MessageBox.Show("Completed");
}
}
I have created a delegate on the code:-
public partial class Form1 : Form
{
private delegate void DELEGATE();
public Form1()
{
InitializeComponent();
}
private void simulateHeavyWork()
{
Thread.Sleep(100);
...lines of code to perform some search logs operation..
....
}
}
The functionality I want to achieve is that progress bar should report the progress of my function simulateHeavyWork() which is actually using UI thread as it needs to take input from my form controls and update it as well.
Now the problem which is happening is that code is actually calling simulateHeavyWork() and gives the output that is updating ui controls and work is done. (Note: I have used delegate here to avoid error cross controls running on ui thread as my function needs to use UI controls.)
Once that is done, it starts updating progress bar and which is wrong and looks like it calls simulateHeavyWork again and again with the gap of sleep(100).
user3222101, as Andy stated before, you are running simulateHeavyWork() continuously. Moreover, by calling Invoke you are running this method in the UI thread which cause an extra sleep in the UI thread. Basically Invoke uses the message loop (pump) of the Control you use it on (Form1 in that case) and put your delegate to the queue of the UI thread in order to execute. This is not a good practice I think, due to the Sleep() call and time consuming log operations in your simulateHeavyWork() method.
I hope, understand you problem clearly.What I suggest is separation of the time consuming log operations from UI thread. Do not spend the valuable time of UI thread with slow and boring I/O operations. Get the values from the controls (using Invoke in the BackgroundWorker as I will explain below), do whatever you want in BackgroundWorker and update your GUI (again using Invoke) without touching the UI thread for this kind of heavy tasks.
As Andy suggested, you can pass data via the parameter of RunWorkerAsync and you should create a class which can store any data you need (because it accepts only one parameter). However, you can get the values from your Form whenever you need from another thread by using Invoke. Invoke
method also returns the value from your delegate (please see the example at the link below) and this gives you a chance to get the values of your controls on the form. Create a delegate which returns an object of type class that you crated for RunWorkerAsync and use this values in the BackgroundWorker thread. Please, have a look at the example in here.
public static string GetTextThreadSafe(this TextBox box)
{
return GetTextBoxText(box);
}
Also, example uses Func<...> in order to return value.
By this way you can sleep (in BackgroundWorker thread) for a while then get the values from your controls (current values) and do whatever you want (again in BackgroundWorker thread). I think, this improves your code.
From your question: "which is wrong and looks like it calls simulateHeavyWork again and again with the gap of sleep(100)."
Of course it calls. Just look at your code:
for (int i = 0; i <= 100; i++)
{
Delegate del= new DELEGATE(simulateHeavyWork);
this.Invoke(del);
So you are calling simulateHeavyWork 100 times here. And since you've typed Thread.Sleep(100); in the body of simulateHeavyWork - gap between calls is about Sleep(100)
I know that this question had been asked 100 times before, but all the answers I read didn't worked for me. So, I'll try my luck and ask again.
I have a SliderBar that calls a method on the ValueChanged event.
In this method I do some stuff that takes time, and I want that in this time the user will see an "working" ProgressBar (IsIndeterminate=true).
Unfortunately, I don't succeed to make the ProgressBar start working (in the UI) until all the method loops finished.
I tried threads, BackgroundWorker and async Tasks but with no success..
What am I doing wrong?
This is the method:
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e){
WorkingBar.IsIndeterminate = true; //change the progressBar
SqlAThread = new Thread(SqlAStart);
SqlAThread.Start();
}
The thread:
private void SqlAStart()
{
... //do some stuff
}
In Slider_ValueChanged you start a new tread to run the time-consuming SqlAStart() method, but SqlAStart immediately pushes the work back to the UI thread (via Dispatcher.Invoke()). Therefore, your UI hangs and you don't see any ProgressBar progress until the work is done.
In SqlAStart, only do a Dispatcher.Invoke() where you need to update the progress bar:
private void SqlAStart()
{
ServerThread = new Thread(HttpSrv.listen);
ServerThread.Start();
...
this.Dispatcher.Invoke((Action)(() => {
WorkingBar.Value = ...
}));
....
}
This is quite easy using IProgress<T>:
private async void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (State.Value > 0)
{
var progress = new Progress<int?>(value =>
{
WorkingBar.IsIndeterminate = (value == null);
if (value != null)
WorkingBar.Value = value.Value;
});
await Task.Run(() => doWork(progress));
Task.Run(SqlAStart);
}
...
}
private void SqlAStart(IProgress<int?> progress)
{
ServerTask = Task.Run(HttpSrv.listen);
...
}
private void doWork(IProgress<int?> progress)
{
if (progress != null)
progress.Report(null);
...
}
Note that you should (almost) never use Dispatcher, Thread, or BackgroundWorker in modern applications.
Rather than type out the whole lengthy process, I'd invite you to take a look at my answer to the Progress Bar update from Background worker stalling question here on StackOverflow. It demonstrates how to correctly use a BackgroundWorker object to update the progress value of a ProgressBar.
You may also like to view the BackgroundWorker Class page on MSDN for more detailed information.
I just had an interview 5 minutes back. I was given this scenario and he asked me the question on how to handle this in C# 1.0 or 2.0. He said there is a basic feature to handle this, I wasn't sure. Can somebody please help :(
Question:
There are 2 text boxes in Winform application and a button. One text box takes input value and when button is clicked, it process input in server which takes hell lot of time and finally displays the result in another textbox. As it takes very long time in server, the UI shouldn't be interupted, how do you handle this scenario he asked me :(
Answer I gave:
I told multithreading and said about async and await. He was expecting a simple way of handling this in C# 2.0 thing. I was guessing about asynchronous delegates. He wasn't convinced. Please someone explain me with little understandble code :)
You would run the long running process in a separate thread to the UI to prevent it hanging, perhaps a BackgroundWorker would be used for example: -
bgWorker.RunWorkerAsync([DATA TO PROCESS])//Passing in data to operate on
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
MyObject obj = (MyObject)sender;
//
// Do some work with the data on the server
//
// Report on progess, is it done?
bgWorker.ReportProgress();
}
You could also have a work complete method
private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Work is complete, notify user
}
You could also use a ThreadPool, which requires a little more set up but i find is more flexible. For example: -
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), [DATA TO PROCESS]);
Interlocked.Increment(ref workItems);
workItems would be a count of the number of items left to process, this could be used to keep track of whether the task is complete or not. We then define a DoWork method where we process the data and decrement our workItems counter. Once an item has been processed, we report progress via delegates such as: -
private delegate void ThreadDone(MyObject obj);
private delegate void TaskDone();
public void DoWork(object sender)
{
MyObject obj = (MyObject)sender;
this.Invoke(new ThreadDone(ReportProgress), result);
Interlocked.Decrement(ref workItems);
if (workItems == 0)
{
this.Invoke(new TaskDone(WorkComplete));
}
}
Report progress might look like this: -
private void ReportProgress(MyObject obj)
{
if (workItems >= 0)
{
//Job isn't complete, report progress
}
}
private void WorkComplete()
{
}
In .Net 2 winform applications, the simplest solution is to use a BackgroundWorker. Its events are raised on the UI thread so you don't need to do any marshalling yourself.
The usual pattern looks like:
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += delegate(object sender, DoWorkEventArgs e) {
try {
e.Result = server.LongRunningOperation();
}
catch(Exception ex) {
e.Error = ex;
}
};
bg.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) {
//update UI
};
bg.RunWorkerAsync();