Windows 7 Home Premium
Visual Basic
Is there a way to suspend execution of a program, but keep event handlers running?
My Visual Basic console application watches for file events, and handles the events with the familiar event handlers.
Current algorithm:
1. Create FileSystemWatcher
2. Set up event handlers
3. Wait for console input from the user, then exit.
Can I replace the last step with a system call to suspend execution of the foreground, while the event handlers continue reacting to events?
Here's an outline of the code (with many lines removed).
Dim watcher As New FileSystemWatcher() 'Create a new FileSystemWatcher
AddHandler watcher.Changed, AddressOf OnChanged 'Add event handler
watcher.EnableRaisingEvents = True 'Begin watching
'I wish to replace this with a system call to suspend
'execution, but keep the event handlers running.
While Chr(Console.Read()) <> "q"c 'Wait for the user to quit
End While
It seems like you're trying to create a service. To do that, the easiest way is probably to create a new project based on the "Windows Service" template and migrate your existing code.
MSDN docs: http://msdn.microsoft.com/en-us/library/d56de412.aspx
Related
I am using the ItemAdd event to watch for new Outlook emails. Does this event work while the application is closed?
Currently, my macro launches upon initial startup using the "Application_Startup()" event, and then initializes a class module containing a sub routine that is trigged with the "ItemAdd" event. If I close Outlook, will this macro still be watching for a new "ItemAdd" event?
Thanks!
No, it will not - the event is fired by the application only, so no application - no event.
Keep in mind that if this is a cached profile, these events will fire on application startup when the cached mailbox (OST) is updated. You can also work around this by processing all unread emails on startup (assuming they stay unread). Or you can persist the MailItem.ReceivedTime property of your last processed message and process all emails newer than that on startup.
I'm trying to change the text drawn on a Button at the beginning of the click event handler. No matter what I do the text doesn't change until after the event handler method finishes. I've tried calling the button's update, refresh, and invalidate methods and also tried calling Application.DoEvents afterward.
The only thing that works, which I don't want to do, is to set up a timer so that the click event handler ends, the button text updates, then the timer ticks and THEN I do everything else I wanted to do in the click handler in the timer tick handler instead...
The problem is that your user interface "hangs" while your long operation is executed on the UI thread. You could solve this by running your long operation in a background thread, for example, by using a BackgroundWorker in your button event handler:
Dim bw As New BackgroundWorker()
AddHandler bw.DoWork,
Sub(sender, args)
' Do your lengthy stuff here -- this will happen in a separate thread.
' If you want to do UI operations here, you need to use Control.Invoke.
End Sub
AddHandler bw.RunWorkerCompleted,
Sub(sender, args)
' We are back in the UI thread here.
If args.Error IsNot Nothing Then ' If an exception occurred during DoWork,
MsgBox(args.Error.ToString()) ' do your error handling here
End If
' Re-enable your button and change the text back here:
...
End Sub
' Disable your button and change the text here:
...
bw.RunWorkerAsync() ' Start the Background Worker
(Of course, if you don't like AddHandler, using an instance WithEvents variable for the BackgroundWorker and the Handles keyword is just as fine and more typical for VB.)
Note that, in this case, the user can interact with your user interface while the operation is running. This can be a good thing (you can add an "interrupt" button that sets a flag which is checked in your long operation), but you need to make sure that no bad things can happen, e.g. deactivate the button, so that the same operation cannot be started twice.
All UI updates have to come from the UI thread. The event handler is called (or invoked) by the UI thread when it detects an event (such as button pressed) occurs. The UI thread takes care of updating the UI after the events.
I have a background worker control on a form.
In this form I have another form that shows a progress:
Private _fWait As frmWait
I am updating this form, change its label to tell the user what is currently going on.
When the background worker is finished, I want to close this form _fWait.
I am using
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'do the background worker stuff. I have not stated it here because it is not important
_fWait.Close()
_bDone = True
End Sub
But I am getting the error "Invalid cross-thread access: The access to the control frmWait occured from a diffent thread than the thread it was created by." on the line "_fWait.Close()".
Can somebody tell me what I did wrong?
Thank you!
When you call _fWait.Close() is has to be called on the UI thread whereas the BackgroundWorker1_DoWork handler will be running on a different thread which is why you are getting the error. There are two options for closing the form:
1) Continue to close the form on the DoWork handler but marshal the request onto the UI thread using something like the code below:
this.Invoke(() => _fWait.Close());
It's been a while since I've done VB, so you'll have to convert the C# code into VB...sorry.
2) Handle the RunWorkerCompleted event and close it there. If you BackgroundWorker was started on
the UI thread, then the RunWorkerCompleted will also be called on the UI thread.
If I remember right the ProgressedChanged event will also be called on the UI assuming that the BackgroundWorker was created on the UI thread. If the BackgroundWorker is created another another thread, then the RunWorkerCompleted and ProgressChanged will also be called on a separate thread and you will have to marshal calls to the UI as described above in step 1.
In simple programs, you can ignore cross-thread errors by adding this to your Form.Load method:
CheckForIllegalCrossThreadCalls = False
Note that it can cause problems when running multiple asynchronous threads that access shared data, so don't use it indiscriminately.
If multiple threads cause a shared routine to run, use SyncLock to prevent multiple simultaneous instances.
Ok I am using a vb.net dll class (not a form application).
In this class I am using a method that creates a timer and in the end will call a method that will throw an event.
timerDriver = New System.Timers.Timer()
timerDriver.Interval = 500
timerDriver.Enabled = True
AddHandler timerDriver.Elapsed, AddressOf DriverLicenseInTray
I'm gonna describe part of the process as if it were working
So the user presses a button on a .asp page that starts the scanner. Once the scanner has been started, the timer process is constantly listening without locking out the page (basically this process does not effect anything the user is doing). Now, the software is watching for a card to be inserted into this scanner. As soon as this is true, it calls a method that processes the card. After the card has been processed it calls RaiseEvent ProcessCard which throws the event to a .asp page that has an appropriate event handler.
The issue I'm having is RaiseEvent. It is raising it on the wrong thread because of the timer. Does anyone know how to fix this?
I've searched and I see that I will probably have to use a delegate BUT i don't have Me.Invoke or anything.invoke. and if i'm right, invoke is what fires the event on the main thread? I've searched the msdn pages like crazy and their fixes are not fixing mine.
I know that the RaiseEvent to the .asp is working because if i throw that on the main method, before the timer, the .asp page catches it.
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