VB.NET DOEVENTS - vb.net

I have a VB6 app, which does a lot of processing in the form_load. A call to DoEvents ensures that the form loads before the processing is complete. However,this does not appear to work in VB.NET i.e. in the following code, the loop finishes befoRe the form is loaded, even though I have called DOEVENTS:
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
For i = 0 To 100000
Application.DoEvents()
Dim Test As String = "Test"
Next
End Sub
What have I missed?

Your statement:
A call to DoEvents ensures that the form loads before the processing is complete
To the best of my knowledge, this is NOT true. The form "paints" before processing your load event - the processing (that is loading) is still not complete. All that is ensured by a call to DoEvents is OTHER messages get a chance to be handled when you are in the middle of a long processing. MSDN's help of DoEvent() describes it as:
Processes all Windows messages currently in the message queue.
Also, it specifically states:
Unlike Visual Basic 6.0, the DoEvents method does not call the Thread.Sleep method.
I believe it might be risky for you to handle your requirement in the Load event. Just a search for "Application.DoEvents in load" in google talks about bad experiences for many. I suggest you can explore handling your requirement in Shown event.

DoEvents in VB.NET should be actively avoided.
Have a look at DoEvents in .NET and Stop DoEvents and DoEvents is Evil to see why.
It is a common misconception that this does the same as the VB6 DoEvents. In almost all cases what you want to achieve can be done in some other way in .NET without the need to call DoEvents.
Your best bet is probably a BackgroundWorker object have a look at this example to get you started.
A point to note though is that you can't update controls on your form from a background worker without using a delegate - but that is another question...

You should use a BackgroundWorker component in order to do lots of background work without freezing up the user interface in VB.Net. Look at this MSDN tutorial How to run an operation in the background

Related

DoEvents is used yet application is not responsive

In my application, I call a process to update software - which is stored within its own class. Even thou I have been writing Application.DoEvents() in few places for some reason the label in the update form is not updating and the form itself is inactive.
Namespace software
Public Class updater
Public Function UpdateSoftware(ByVal url As String, ByVal downloadFolder As String) As Boolean
Application.DoEvents()
Thread.Sleep(1000)
frmUpdate.lblResult.Text = "Update is about to begin"
Thread.Sleep(1000)
frmUpdate.lblResult.Text = "Downloading data"
Thread.Sleep(1000)
Application.DoEvents()
frmUpdate.lblResult.Text = "About to start the writing process"
Application.DoEvents()
frmUpdate.lblResult.Text = "Software was updated, please restart your device."
End Function
End Class
End Namespace
I can't figure out why you were calling DoEvents in those specific locations, since none of them will have any visible effect where they are. The first one happens before any labels are changed, so allowing the form to refresh there is pointless. The others are at the very end, after all the long-running work is already done (the three sleeps). So, while they will allow the form to refresh before execution leaves the method, it will very very shortly be leaving the method anyway, so there's no point in doing it there either. The only place where it would even be applicable to call DoEvents would be between two long running things. For instance, if you did this, you'd notice a difference:
Public Function UpdateSoftware(ByVal url As String, ByVal downloadFolder As String) As Boolean
Thread.Sleep(1000)
frmUpdate.lblResult.Text = "Update is about to begin"
Application.DoEvents()
Thread.Sleep(1000)
frmUpdate.lblResult.Text = "Downloading data"
Application.DoEvents()
Thread.Sleep(1000)
frmUpdate.lblResult.Text = "About to start the writing process"
frmUpdate.lblResult.Text = "Software was updated, please restart your device."
End Function
You need to understand, in .NET WinForms (as well as in WPF), the UI is running on a single thread. What I mean by that is, if one of your event handlers contains code that takes a long time to complete, the UI will be frozen for the entire time that event handler is executing. The UI refreshing is completely blocked until the last event handler finishes doing whatever it was doing. DoEvents is somewhat of a hack way of getting around that (and a dangerous hack, at that). Each time you call DoEvents, it returns control back to the form to handle whatever else it has queued up to do (such as repainting the screen and handling user input) and then execution is returned to the original event handler so it can continue where it left off. That means, each time you call DoEvents, it allows the form to repaint at that point, but the event handler still blocks the UI in between all of the DoEvents.
As others have already implied, using DoEvents is highly discouraged. Not only is it less effective, it can cause all sorts of unexpected behavior. In pre-.NET versions of VB (e.g. VB6), DoEvents was often the only option, but in .NET, multi-threading is relatively easy. There may be occasions where DoEvents is legitimately still useful, but they should be very few and far between and only implemented with great care and caution.
There are two recommended ways of implementing multi-threading in WinForm applications. The original method, which still works well, is to use a BackgroundWorker component (you'll find it in the WinForm designer tool-box). The BackgroundWorker raises an event on a different thread so that you can do all your long-running work in that event handler, without it blocking the UI. Then, when it's all done, it raises another event, back on the UI thread so that you can update the UI after the work is complete.
The newer method, which is much cleaner and easier to read, but a little more sophisticated, is to use the Async and Await keywords to make all your long-running methods, and your event handler that calls them, asynchronous.

How to update a rich text box from a background worker using a delegate

Ok I'm pretty new to using threads but so far I've managed to get the following:
Private Delegate Sub dlgUpdateText(text as string)
Private Sub UpdateStatus(text as string)
If rtxStatus.InvokeRequired then
Dim dlg as new dlgUpdateText(AddressOf UpdateStatus)
Me.Invoke(dlg, text)
Else
rtxStatus.text = text
End If
End Sub
and from my Async BackgroundWorker I call
UpdateStatus("Some text")
which seems to work ok however in my original code (which generates errors because I'm updating the control from the wrong thread) I used the following code to append to the (rich)textbox:
rtxStatus.Select(rtxStatus.TextLength, 0)
rtxStatus.SelectionColor = Color.Red
rtxStatus.AppendText("Some error occurred gathering data")
My question is how should I modify my new code to allow me to do this rather than just replace the text? I have read several guides on using delegates but I'm still lost on a few points so I don't really know what's going on with the code I have.
Bonus questions (which probably serve best to show what needs explaining to me!):
What does the Delegate Sub actually do? It doesn't seem to serve any purpose other than hold the property (text) that was already passed to the main Sub (UpdateStatus)?
What is happening when Me.Invoke is called? Me is the current form so when I pass the Delegate Sub and the text where is it specified that the text should be passed to the rtxSTatus.Text property?
UpdateStatus runs in the main thread (?) and is called from one of the background worker threads so why is the Invoke even necessary or is the UpdateStatus Sub run under the background thread that called it? When I altered the text that is applied in the Else statement to see which was run it seems that Invoke is never used to change the text in the box.
Any help would be really appreciated, I'm completely baffled by this - thanks!
Rather than creating a delegate I would suggest using the existing methods offered from a backgroundworker. The backgroundworker provides two methods to access the main thread:
The ProgressChanged event to update the main thread during backgroundworker processing and the RunWorkerCompleted event to update the main thread once the backgroundworker process is complete.
You can find this information and how to implement it from the following link:
http://msdn.microsoft.com/en-us/library/ywkkz4s1.aspx

Backgroundworker - UI still not responsive until BGW completed

I implemented a BGW to my application in hopes of speeding up loading time for the starting window(40+ controls)
I will not post my whole code as it's far too long but will give you the gist of the code. I split big function calls that take time to complete alongwith a handful of controls and moved them into the BGW in hopes of asyncronously loading controls to help quicken the process.
It is understood that I have to move UI changing code to the ProgressChanged event or RunWorkerCompleted event, which I have done. I originally had all code thrown into the DoWork event and it was extremely fast but found out it's not safe so I had reworked it to move all UI-related oode to the ProgressChanged. It's not nearly as fast now and it seems that the BGW controls wait until the UI thread completes prior to changing the controls in the BGW_ProgressCHanged event. I never saw this 'lag' between the two when I had all the changes in DoWork. What can I do about this? Or can I at least had the BGW update the controls realtime rather than waiting for all controls are completed before updating all controls?
The responsiveness is lower as well as it locks up the window to wait for the BGW controls to update. Just looking for what could possibly be happening
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
SyncLock <globalVar>
BackgroundWorker1.ReportProgress(0, "Tom")
End SyncLock
End Sub
Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
Dim value As String = DirectCast(e.UserState, String)
Select Case e.ProgressPercentage
Case 0
lblName.text = value
lblName.Visible = true
End Select
End Sub
You removed all evidence of the problem in your code, but the diagnostic is an excellent match. You have a fire hose problem. Your code is calling ReportProgress far too often.
Things go wrong when your ProgressChanged event handler needs more time than the time between ReportProgress calls. Which is like drinking from a fire hose, no matter how fast you swallow the water, you just can't keep up with the flow.
Which is what the UI thread experiences. When it finishes the call to your ProgressChanged event handler, there's yet more water, yet another request to call the handler. That relentlessly continues without the UI thread ever being able to keep up. It now doesn't get around to doing its normal duties anymore. Which means that your UI stops updating, paints are no longer performed. And it doesn't respond to input anymore.
This can last for a while after the worker thread stopped running, the UI is still trying to work down the backlog of requests. When it finally gets there, the UI suddenly springs back to life.
A simple way to diagnose this condition is to add this method call after the ReportProgress call:
System.Threading.Thread.Sleep(45)
Which slows down the worker thread enough to limit the number of ReportProgress() calls to no more than 21 per second. Which is plenty fast enough for human eyes, anything faster just looks like a blur so is wasted effort. If that fixes the problem then you found the cause.
Using Sleep() like this is otherwise an ugly Q&D solution for the problem, it of course also slows down your worker so its gets less work done. You'll have to improve your code so that this doesn't happen and just makes less ReportProgress calls.
One thing you might want to add before starting the worker:
Me.SuspendLayout()
Then, in the RunWorkerCompleted event:
Me.ResumeLayout()
That should suspend all layout logic until all the work is done, then update the entire form in 1 operation.
EDIT
Replace
BackgroundWorker1.ReportProgress(...)
With
DirectCast(sender, BackgroundWorker).ReportProgress(...)
And get rid of the synclock.
EDIT2
The correct way to feed the data to the DoWork event is through the DoWorkEventArgs.
Start work like this:
BackgroundWorker1.RunWorkerAsync(<globalvar>)
And access it like this:
Dim globalVarData As Object = e.Argument

running vb.net in a new thread

how do I force a particular set of vb.net codes to run in a new thread or process.?
Edit 1: I am trying TTS in vb.net but whenever click the play button , The whole program freezes and I cannot do anything else until the speech is over
In a comment below you mention the library you are using and that changes this whole answer.
Answer to your problem:
In your case since you are using the SAPI.SpVoice library you don't need to do any work related to spinning up background threads and such since that object support asynchronous playback. Check out the arguments of the Speak method. Here is the documentation: http://msdn.microsoft.com/en-us/library/ms723609(v=vs.85).aspx
Answer to your question as it is posed:
The simplest method is to use a background worker process to run some code. This will allow your program to run some long process and not block the UI thread. The background worker even provides events to notify your UI thread of it's progress.
Here is an link to MSDN http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
The background worker is a simple way to spin off some work onto another thread, there are other tools for more complex scenarios. In essence you create an instance of a background worker object and add your long-running code to a function that is created to handle it's DoWork event. There are ProgressChanged and RunWorkerCompleted events that should be handled as well. There are methods that can be called to cancel the process. The MSDN link above provides a couple of good complete code examples.
Wrap the "set of codes" into a method and dump it onto the ThreadPool
ThreadPool.QueueUserWorkItem(AddressOf MyMethod)
the ThreadPool suggestion worked for me for a WP7 Silverlight app:
Private Sub AddAnagrams()
ClearAnagramsList()
UpdateAnagramsCount() 'update the count first, then add the items
ShowCalculating(True)
ThreadPool.QueueUserWorkItem(AddressOf UpdateAnagramsOnUIthread)
End Sub
Private Sub UpdateAnagramsOnUIthread()
Dispatcher.BeginInvoke(AddressOf UpdateAnagrams)
End Sub
Private Sub UpdateAnagrams()
ListAnagrams.ItemsSource = _Combinator.CombinedItems 'this is a virtualized datasource
ShowCalculating(False)
End Sub
Private Sub ShowCalculating(ByVal flag As Boolean)
LblCalculating.Visibility = If(flag, Windows.Visibility.Visible, Windows.Visibility.Collapsed)
End Sub

what is function that i can use instead of Do events (used in vb6.0) in (vb2010)

for a=0 to 1000
lable.text=a
next
Above loop does not update the text status of lable, while loop is running, it updates only at the end of for loop, but I tried with vb6.0 it is possible by using Do events. But I don't know what is the function in VB2010 beta 2.
Any ideas on how to implement this loop in VB2010?
You could try
Application.DoEvents()
Or even
lable.Refresh()
You need to change the way you think about this sort of problem in .NET - DoEvents was a hack to deal with the lack of threading in VB, useful but not a good solution.
To run a processor intensive task while keeping the UI responsive you need to use multi-threading, you kick off the intensive work in a separate thread and update the UI in the main thread.
Easiest way to do this is using the BackgroundWorker class http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(VS.100).aspx
Your loop would raise ReportProgress events which your UI code would use to update the label.
You can use Application.DoEvents() in .Net - but you really probably shouldn't. It can cause all sorts of strange behaviour that will be a nightmare to debug. I've seen button's OnClick event firing when the button is disabled (as an example) and ultimately traced it back to calling DoEvents().
If your goal is really just to count and update a label - use a Timer.
If you are doing meaningful work - you should look into multithreading.
The BackgroundWorker class makes this pretty darn easy - you can have it report progress and update your control. If you aren't using an old version of the .NET Framework - you can use a Task as well.
Having said all of that - no matter what approach you take - you won't be able to see much of anything inside a loop like you've provided in your example. It will simply happen too fast (unless you use a timer and set the Tick value appropriately).
Example Using a Timer
The easiest way to do this is in the Form Designer - drag a Timer Component (under the Components group) onto your form. You can edit the properties and give it an appropriate name and set the Tick value to something like 500 (that's the tick interval in milliseconds). Set the Enabled value to True.
Now click the Timer control, and pull up the Properties window. Click on the Events Icon and double click the Tick Textbox. This should create the default handler for you.
Modify the code to look like this:
Private A As Integer
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
' Update the text
Label1.Text = A.ToString
A += 1
' Stop the timer
If A >= 1000 Then
Timer1.Enabled = False
End If
End Sub
Your question is not very clear, but I'll try to explain what I understood. The loop actually updates it, but it happens so fast that you only see the final value. I don't know the VB equilevant of sleep() method, but you should be able to find it in web pretty quickly.
Its not the text is not getting changed but its getting overwritten when you loop it each time. If you want to display 0 to 1000 in the label then you have to append the value.