When backgroundworker completes, how to give priority to update the UI thread? - vb.net

I have a background worker I'm using to run through a large function in hopes of quickening my window load and responsiveness. When I put this function in the backgrounderworker's doWork event I'm just wondering if there's anyway I can prioritize that text to update as soon as the BGW is complete rather than waiting for the UI thread to finish and then update the textbox. Is this possible? I only ask because it seems like it's taking quite some to update the textbox after running through the function(which takes about 1.5-2s) but even if I start the BGW to begin even before the window loads(takes a good 5 seconds to load), it's still the last item on my window to update so I would like to(if possible), halt the UI thread from updating the UI until I update with what this function returns, then continue updating the rest of the labels.
Also, is there anyway to update two separate items at once or is it restricted to the one UI thread?

If you want to update UI elements, you have to do it on the UI thread. When the BackgroundWorker is finished, the RunWorkerCompleted event is raised on the UI thread. If the UI thread is busy doing something, then the completed event has to wait. In general, there's no safe way to interrupt the UI thread, make it process the RunWorkerCompleted event, and then go back to what it was doing.
UI elements must be updated from the UI thread. So you can't update two separate items at once.
I don't know how your initialization is structured, but if you have one group of items that you can initialize before the BGW is finished, and another group that can't update before the BGW is done, then do the first group and stop. Then have the RunWorkerCompleted handler do its update and all the rest of the updates. So it would look something like:
FormLoad()
start background worker
do first group of updates
RunWorkerCompletedHandler()
update from BGW calculation
do rest of updates

Related

Cannot update User Control Label Text from parent event until the event method reaches return statement

The main form of my application has an event that gets triggered upon completion of a certain task. The event completion launches a background thread and the called method in that thread runs a loop which takes a while to complete. This loop updates (or is supposed to update) the user on what's going on during its run by editing the label->Text property of the UserControl along with a percentage of completion in a different label in the same UserControl. There are some more labels in this UserControl that are updated, but are not of the concern for this question.
Here is how the methods and statements are called.
Event Completed -> Background Thread
Background Thread -> Process()
Process() -> for loop()
for loop() -> UserControl->SetMessage(System::String^ msg) and UserControl->SetPercentage(int Percentage)
(1) UserControl->SetMessage(System::String^ msg) -> stores msg in a private UserControl member and executes this->Invoke->SetMessage_sub()
(2) UserControl->SetPercentage(int prcnt) -> stores prcnt in a private UserControl member and executes this->Invoke->SetPercentage_sub()
(1) SetMessage_sub() -> label1->Text = _msg;
(2) SetPercentage() -> label1->Text = _prcnt;
However, I found that the labels were not getting updated for as long as the loop ran. The labels only updated once the loop finished its run inside Process().
I used the System::Console::WriteLine method to figure out where the problem occurs. I found out that all the methods were being called. But the execution would stop at where the program would reach label->Text property. Please help me out.
I have run into a similar problem recently and found that the GUI update calls must be made from either a thread running in the background or a background worker. Try calling the method that updates your GUI from a background thread or a background worker.
Edit 1 - it sounds like you've already tried a background thread. Try using a BackgroundWorker object to accomplish the task.
Edit 2 - upon re-reading your question, it occurred to me that the problem you are facing is the GUI not loading until the event method has returned. I encountered the same problem and asked my question here. To my surprise, all I got was downvotes and no answers. A comment tried to refer me to using BGWorker class to update GUI but none of them read my question carefully. I know background threads and background workers. I have tried both but the GUI does not update until return is called from the event method. In my case, after calling the BackgroundWorker to do the processing, I ran an empty while loop in the event method and called break when the BGWorker finished. But the GUI never updated until break was executed. So, my solution was to create a separate event for the processing and processing completion. The completion of the initial event calls the processing method and then processing method's completion calls the processionf completion event method.

Show a progress bar while a function runs in a loop until it returns a value

I have a function that runs an sql query for data that may or may not be there. Since I need to run this function continually until it returns the proper value how can I run a progress bar until the loop finishes.
status = Logic.ProcessResource(currentInstance)
While status.woID.Count <= 0
status = Logic.ProcessResource(currentInstance)
End While
How can I run this and show another form with a progress bar until the loop exits?
My comments as an answer...
Put that code into a different thread, then use a ProgressBar in "Marquee" mode to indicate an operation that is ongoing, but has no known ending time.
Yes...but you still need to put the query/loop in a different thread...otherwise the main UI thread will to be to busy to animate and remain responsive to the user.
Look at the BackgroundWorker control, or using a Task, with Async/Await.
You'd show the form, start the worker, wait for worker to finish, then close the form. The BackgroundWorker() has UI friendly events like RunWorkerCompleted that are already marshaled to the UI thread for you.

How to update a NSTextField Value during an action?

I am running a lengthly task in an Action and I would like to have a display of where I am at. For that I created a Text Field and I tried it with setStringValue:
[textField setStingValue: [NSSting stringWithFormat:#"%ld",currentValue]]
The code works but unfortunately it is not updating the NSTextField after every iteration but rather when the whole Action is done.
What am I doing wrong?
This is because applications with the Cocoa framework use an event loop to perform operations, and events occur in a completely serial fashion.
An event is basically any kind of action that the framework designer could not predict or found convenient to have run in a delayed manner. Since you can't predict when clicks will be performed, they need to be considered events; and for efficiency reasons (since you don't want to repaint a component multiple times if you don't need to), the repaint actions are events too.
Your action runs in response to a user event (for instance, a click on a button is an event) and therefore blocks all other events waiting in the queue until it's complete. However, components are repainted in response to a different, framework-triggered event, and as such the text field must wait until your action completes to repaint itself. This is why you cannot visually change the value of a text field from inside an action.
In order to notify your user of the progress of your task, you'll need to run it on a different thread. There's a lot to say about threads, so you should probably read some about them. I'm also sure that there are plenty of examples of how to run a long action in a background thread and update the UI accordingly for Cocoa all over the Internet.
When you click on a UI component, and it enters the Action block, the code is running on the main thread, the same thread that is painting the UI. If you run a long running operation in that block, it isn't going to paint until you are done because it is busy doing whatever you have it doing - you have hijacked the paint thread.
As said elsewhere, you need to spawn another thread, and then have the new thread perform the long running operation, and occasionally send messages to have the UI be updated by the main thread.
As a next step, go read the Apple documentation on NSThread, specifically:
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
Be aware that threading is a non-trivial domain area, and be ready for some wierd behavior if you aren't careful.

Vb.Net waiting for process 30secs

I have three events to fire on button click.
after running the first event i want to wait for 30sec to wait for nex event to fire.
how i can wait( i mean looping for 30 secs).
Thanks,
Nag
You can try this to your code directly:
MessageBox.Show("Test") ' Execute your method 1
System.Threading.Thread.Sleep(30000)
MessageBox.Show("Test2") ' Proceed with the other one :)
If you wait on the UI thread you'll block the whole UI and Windows will show your application as non-responding.
Better to:
Update the UI to show it is busy, including disabling controls to block user input.
Use a timer control (details depend on WinForms or WPF) to trigger an event after the time delay
Do the work in the timer's event handler.
If the work is CPU or IO intensive (ie. likely to block for more than a few tens of milliseconds) then perform the work in the threadpool (eg. BackgroundWorker component). Remember you'll need to use Control.Invoke to make any changes to the UI from the worker thread.
You can use Thread System.Threading.Thread.Sleep(30000); to hold execution.
use a timer for it and set an interval of 30 seconds to timer (1sec = 1000)
timer1.Interval=30000

Progress "bar" using threads in vb.net

I currently have a program that runs several "intense" queries. I added a textbox and presented status updates when a query was starting, eding and how many were left. This would suite my need, but the textbox doesn't actually display anything until all the queries are finished. It then displays all the updates at once. I'm assuming updating the textbox in another thread would solve this issue, and that is where I am lost. How can I use a thread that receives a message from the main form running the query and have it display it in the textbox?
The BackgroundWorker component suits your need (sample code is there in the MSDN link). You handle its DoWork event and perform the actual query in it. You report the progress by calling its ReportProgress method. To display the reported progress, you should handle its ProgressChanged event and update the UI. You start the job by calling the RunWorkerAsync method of the background worker. Using BackgroundWorker relieves you from manually starting and stopping threads and communicating with the UI thread to update the progress bar.
BackgroundWorker is a good general-purpose method for doing intensive work on a background thread. But, since your question sounds like you are doing database operations, it might be easier to use the native support for asynchronous operations in ADO.Net. You could use callbacks for the progress bar.
The easiest way to do this is making use of BackgroundWorker, handling it's DoWork event and reporting progress to the ProgressBar with ProgressChanged event.
to start:
worker.RunAsync()
report progress:
worker.ReportProgress(10) 'for 10%
Adding to what Mehrdad and Alex posted, here's how to handle the event raised by the ReportProgess method (ProgressChanged) to update the progress bar:
Private Sub backgroundWorker_ProgressChanged ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles backgroundWorker.ProgressChanged
Me.progressBar1.Value = e.ProgressPercentage
End Sub