Why BackgroundWorker infinite loop stops? - vb.net

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
MsgBox("test")
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
BackgroundWorker1.RunWorkerAsync()
End Sub
Once I click the Button1 ,Messagebox appears.When click okay with "Return" (enter) key it appears again and again...But when I click Return key permanently,almost 5 seconds later programs gives me the run time error.
Error is not English in my computer and I translated it.It is nearly mean "BackgroundWorker is busy,can't do two procces in the same time..."
I know that error.It is because of trying to run BackgroundWorker while it is running.In the code it just start with RunWorkerCompleted event.So it can't start again if "Work is not Completed".Who runs the BackgroundWorker ?

You need to read this post first, it talks about the dangers of re-entrancy and how dialogs (like MsgBox) solve the problem.
Which is what it is not doing in your program. A dialog can only be modal against other windows that are created on the same thread. That worker thread doesn't have any. So there is nothing that stops your Enter key press from also being seen by the control that has the focus. Button1. Note how you can simply use the mouse to select your main window and click the button. Kaboom.
That doesn't go wrong often enough as-is, you can help by leaning on the Enter key so it starts repeating. It will usually be detected by the message box window. But not always, there's a split second between DoWork ending and it starting back up. Just enough to give the UI thread a chance to see the keystroke. Now that Enter keypress operates Button1 and it starts the BGW back up again. So does the RunWorkerCompleted event handler, it cannot be started twice. Kaboom.
That's not the only problem with that dialog, you haven't discovered the other failure mode yet. A dialog needs an owner window, one that it can be displayed on top of. That message box does have one, it has to fallback to the desktop window. Now it is crapshoot which window is going to be in front. Could be the dialog, could be your main window. With the message box underneath your main window. The user cannot see it, has no idea that there is one. No taskbar button either.
Long story short: this cannot work. Only display UI on the UI thread. Only use a worker thread to do non-UI related work.

Related

Set Focus to Form After Me.Show

I've come across a peculiar focusing issue. I have created the following "search" program:
It runs in the background.
When you double-tap the Ctrl key it becomes visible.
You can type in the textbox because the form has focus.
If the form loses focus (I click on my desktop, for example), it disappears after 3 seconds.
I double-tap the Ctrl key again, and again it becomes visible.
But this time, no matter what I try, the form is not focused and I cannot type in the textbox without first manually clicking on the form.
What's particularly interesting is that when I run this program in debug mode from Visual Studios, the program regains focus upon double-tapping Ctrl key and becoming visible, and I can immediately start typing in the text box. However, when I build this program and run it alone, the program appears but does not regain focus upon double-tapping Ctrl key, and therefore I cannot type in the text box until I manually click the form.
After Me.Show() I have tried:
Me.Focus()
Me.Validate()
Me.Select()
Textbox1.Select()
Textbox1.Focus()
The form is topmost and normally running in administrator, but the same problem arises regardless.
The issue can be recreated in a more simple manner. Create a form with
Button ("Button1")
TextBox
Two timers ("hideForm", "showForm") both with intervals of 1000
Code:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
hideForm.Start()
sender.Enabled = False
End Sub
Private Sub hideForm_Tick(sender As Object, e As EventArgs) Handles hideForm.Tick
Me.Hide()
hideForm.Stop()
showForm.Start()
End Sub
Private Sub showForm_Tick(sender As Object, e As EventArgs) Handles showForm.Tick
showForm.Stop()
Me.Show()
Me.Activate()
End Sub
End Class
Click the button, and immediately click on a different window (so the form loses focus). Wait until the form is hidden and shown again. The textbox should have focus. Try typing.
If the program is run in debugging mode in Visual Studios, it works as expected. If you build the program and run it outside of VS, the form will reappear without focus, and you cannot type in the textbox without manually selecting the form.
Sorry for the long-winded explanation. It's a difficult issue to properly describe.
Try the form event handler Activate. Inside that method, you can use setFocus to gain focus for that particular Text Box. I know this answer is too late. But hope this helps someone.
Private Sub Form_Activate()
TextBox1.SetFocus
End Sub
Try an event handler for Form_Activate, and within that handler pass the focus to your textbox.
Instead of Focus, you can also try TextBox1.Select. This SO link provides some additional information and something about the difference between Focus and Select.
Select the Textbox you want to assign a focus to in the Design View Window.
Under the Properties window, set the TabIndex to 0 (zero).
I didn't even have to use the TextBox1.Focus() command. It still bothers me that the TabIndex overrides the Focus command.
What I tried (and worked for me), was to set the Focus() of the Textbox in the event handler Shown() [VB]:
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
Me.Textbox1.Focus()
End Sub
Note: the Select() method just didn't do the job. I hope this helps anyone else that comes with this same issue.

MessageBox launches but does not display

I'm working on a project and I am using a button to show a message box with sample data.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
MessageBox.Show("hi")
End Sub
Simple enough.
However, when you click the button, I hear the sound that the MessageBox has launched, but the form is never displayed.
I know it has launched because if I try to do anything after clicking the button, I'm locked out. I have to press enter to acknowledge the MessageBox before I can continue.
This project used to display the MessageBox, but it has stopped.
I've tried several different areas in code, but whenever I show a MessageBox, I get the same results. Any ideas on what I have done?
never mind, I solved it.
there was a sub that was rendering a picturebox every time the form_paint was called. It overwrote the messagebox on the screen.

How do I disable all exiting in Visual Basic

I'm writing an examination piece of software for my workplace and would like to know how I can trap and cancel key-presses such as:
ALT+F4
WIN+TAB
ALT+TAB
WIN
CTRL+ALT+DEL
I'm aware CTRL+ALT+DEL may not be possible, but if any of this is it'll be a step in the right direction!
Ideally I want to prevent the action, and then open a new form I've created saying 'Unauthorised keypress'
as #SQLHound link relates... us the FormClosing event to handle what happens when a user attempts to close. But if you want to block a boot attempt, then #Plutonix suggestion may help. Something along these lines...
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
Dim splashScreen as New Form
splashScreen.OpenDialog
e.Cancel=True
End Sub

VB.net event handler abort when it is fired again

I have an application written in VB.net. In that application I have multiple forms and lots of functionality. The form the application starts with, is some kind of menu. In the background, I have a list of menu items that a user can see and use to open a new form. It is possible to search through all those menu items via a textbox where you can fill in some text and the code then compares all the menu items names to the filled in text and shows the result. This event is fired on every textchanged event of this textbox. But if the user types in a name that occures a lot (like à 100 times or so) the view takes some time (3 to 5 sec) to display all those results. Now I would like to know if it is possible to abort the first event handler if the same event is called again. That means that if I am typing in the textbox and for the first 4 or 5 letters almost all menu items are matches, so I want to abort that search and start a new one right away. Is there any way to detect that the same event is called again and abort the currect one to make the new one start right away?
Thanks in advance for reading this and helping me solve this problem!
In order to accomplish this, you are going to have to do the work in a separate thread. The primary reason for that is that WinForms are single-threaded. All UI-related events in a WinForm are handled on the same UI thread. As such, there is no way for the TextChanged event to fire again while you are still in the middle of processing the previous event. The UI will be locked up until the first event if finished processing.
However, if you do all of the menu-filtering work in another thread, then your UI will be freed-up to react to user input while you are doing the work. Then your TextChanged event will be allowed to fire before the previous one is done processing.
The easiest way to implement multi-threading in a WinForm project is to use the BackgroundWorker component. You can find it in the form-designer tool box. Luckily, the BackgroundWorker component has some properties and methods which are useful for implementing the cancellation as you described.
For instance, here's a very simple example. In this example, every time the text in TextBox is changed, it starts BackgroundWorker1 performing some work. The work that it does is to simply wait two seconds and then copy the contents of TextBox1 to TextBox2. If the text changes again before those two seconds are complete, it cancels the bacground work and starts it again from the beginning.
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
If BackgroundWorker1.IsBusy Then
BackgroundWorker1.CancelAsync()
Else
BackgroundWorker1.RunWorkerAsync()
End If
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
For i As Integer = 1 To 20
If BackgroundWorker1.CancellationPending Then
e.Cancel = True
Exit Sub
End If
Thread.Sleep(100)
Next
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If e.Cancelled Then
BackgroundWorker1.RunWorkerAsync()
Else
TextBox2.Text = TextBox1.Text
End If
End Sub
In order for the above example to work, the BackgroundWorker1.WorkerSupportsCancellation property must be set to True.
As you can see, when the text changes, it simply checks the IsBusy property, which determines whether or not the background thread is still working from a previous event. If it is, it cancels it. If it's not, it starts it.
All of the work which needs to be done on the separate thread is done inside the background worker's DoWork event handler. As it is doing the work, it needs to periodically check whether or not it has been canceled. If it has been canceled, it needs to stop what it's doing and set the Cancel property of the event args to indicate that it is stopping because it was canceled.
Once the background work is done, (whether by cancellation or by completing its task), the background worker raises the RunWorkerCompleted event. The event args for that event have a Cancelled property which indicates whether or not the work completed because it had been canceled prematurely. In the example, if it was canceled, it simply restarts the work from the beginning.
For what it's worth, all of this would be moot if there was some way for you to speed up the menu-filtering algorithm to the point where it's near instantaneous. It may be possible to do that by indexing your menus in something like a suffix array.
Try to add a condition. In your search method, if your text length exceeds some value, call the same event again (like in recursive methods). It should works.
Regards,
Daniel
add some condition on length of search string...like on its Length should be 5 or more
OR maximum results shown at one time should be limited.

Why doesn't a MsgBox trigger a lost focus event VB.net?

I have a timer that each time displays a message box saying "Hello." I also have the code configured so whenever the window loses focus, it should stop the timer that keeps the boxes coming. However, they keep coming.
I have tried a similar thing in a similar program with way too long of code to post here, but what it did was it paused the first time, stop the timer, and when the timer was stopped again, it didn't work correctly. There was also some other code there that had a random element, that displayed a different prompt when a certain number was generated, but once it was generated, it kept using that same different prompt every time.
Is this a error of not enough time to process all the code and it "overlaps" some? I can delay the timer without that much different effects, but I think that my [lower end] CPU that it is running this program on, that with 1.6 GHz that it could handle a timer with a few message boxes. Though, VS is running at the same time, but I shouldn't have to export my code and close VS everytime that I need to test it.
If the problem is not enough time, is there a way that I can prevent my program from "multithreading" or whatever it is doing? It seems like a weird problem, but computers are very weird too. :P
Edit:
By "Focus" I mean the selected window that is the most apparent. For example, my browser is now "focused." I have been informed that the correct term is "selected." I must have been using the wrong type of event trigger... :P
It doesn't generate a lost-focus event because the form doesn't have the focus in the first place. A control on the form always gets the focus, like a Button or TextBox. You could use the Deactivate event instead.
Or just not display the message box when the Tick event fires again. Roughly:
Private ShowingMsgBox As Boolean
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
'' Do stuff
''
If Not ShowingMsgBox Then
ShowingMsgBox = True
MsgBox("yada")
ShowingMsgBox = False
End If
End Sub
The underlying reason for this behavior is that MsgBox pumps a message loop. It keeps normal Windows messages getting delivered, like WM_PAINT that keeps the windows painted. And WM_TIMER, the one that generates the Tick event. The only kind of messages that it blocks are input events, mouse and keyboard messages. Otherwise the reason that Application.DoEvents() is so very dangerous. It does the same thing as MsgBox() does, without disabling input.
Create a new project with a Timer (Timer1) and write this code:
Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
If (Me.Focused) Then
MessageBox.Show("Hello")
End If
End Sub
If you put the mouse over your form, you would see that a message box will popup after the given Interval is over. If you don't click on the accept button and keep the mouse on the form, you would see that no further messages appear: Me.Focus is False. If you click on the accept button, the messages would start poping up; you don't even need to select the form (the focus is transferred automatically from the MessageBox to the Form).
Summary: the MessageBox does make the Form to lose the focus, although it is a kind of a "tricky" lost as far as will automatically come back after clicking on the accept button.
UPDATE: the proposed configuration does trigger a LostFocus event of the form:
Private Sub Form1_LostFocus(sender As Object, e As System.EventArgs) Handles Me.LostFocus
MsgBox("lost")
End Sub
Unlikely the other answers/comments, what I understood from your question is that you want to know the reason and if this is a normal behaviour, rather than getting a working solution to make the form to lose the focus (you are not even describing the exact conditions under which you want this to happen).