This topic contains the following sections.
In this step you'll be adding a user interface to your application. The important things to notice in this step are:
- Running the application
- Handling job manager events
- Working with cross-thread method calls
The first user interface element you'll add is a button that runs the saved QuickBuild application. From the Visual Studio Toolbox, drag a Button from the Common Controls section to Form1. Name this button RunOnceButton and set its text to Run Once.
Double-click the button to create its Click handler, and type the following code:
Private Sub RunOnceButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RunOnceButton.Click
Try
myJobManager.Run()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End SubThe Run method runs all of the jobs in the myJobManager which contains your saved QuickBuild application. The button's Click handler calls Run inside a Try/Catch block to handle any errors that might occur as the QuickBuild application starts running.
Run your program now, and click the Run Once button to make the application run. (Since you're not displaying any output at this point, you won't see anything.) Try clicking the RunOnce button repeatedly as quickly as possible. You should get an error message.
The reason that you got an error when you clicked the Run Once button quickly is that Run is an asychronous method that returns immediately. If you call it again while a job is running. you'll get a CogNotStoppedException error.
To avoid this problem, you'll disable the Run Once button while a job is running and reenable it when the job is stopped. Disabling the button when a job starts is easy enough. All you need is to disable the button in its Click handler:
Private Sub RunOnceButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RunOnceButton.Click
Try
RunOnceButton.Enabled = False
myJobManager.Run()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End SubReenabling the button when the job stops running is a little more complex. A CogJobManager fires a Stopped event when all of the jobs in the job manager have finished running. You'll put the code to reenable the button in the job manager's Stopped event handler.
At the end of the Form1 class, write the Stopped handler for the job manager like this:
Private Sub myJobManager_Stopped(ByVal sender As Object, ByVal e As CogJobManagerActionEventArgs) RunOnceButton.Enabled = True End Sub
Once you've defined the Stopped event handler, you need to make sure that the job manager knows where it is. Use AddHandler to register the handler for the event. The first argument to AddHandler is the event; the second argument is the address of the handler. Add the following code to the end of your Form1_Load method:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
myJobManager = CType(CogSerializer.LoadObjectFromFile("C:\Program Files\Cognex\VisionPro\Samples\Programming\QuickBuild\advancedAppOne.vpp"), CogJobManager)
myJob = myJobManager.Job(0)
myIndependentJob = myJob.OwnedIndependent
myJobManager.UserQueueFlush()
myJobManager.FailureQueueFlush()
myJob.ImageQueueFlush()
myIndependentJob.RealTimeQueueFlush()
AddHandler myJobManager.Stopped, AddressOf myJobManager_Stopped
End SubWhenever you register an event handler, it's a good idea to remove it before you close your program. In this example, the best place to do it is in the form's FormClosing handler, right before you shut down the job manager. The FormClosing handler should now look like this:
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
RemoveHandler myJobManager.Stopped, AddressOf myJobManager_Stopped
myJobManager.Shutdown()
End SubIf you run your program at this point, you will get an error: Cross-thread operation not valid.
Remember that the job manager creates several threads. One of these threads fires the Stopped event that runs the stopped event handler and eventually attempts to reenable the Run Once button. This sequence of events is illegal because a button -- or any other Microsoft Windows Forms control -- can only be accessed by the thread that created that control. The button was not created by any of the job manager threads.
Microsoft provides a way to make thread-safe calls to controls.
Note: You can learn more about making thread-safe calls in this MDSN article
Every control has an InvokeRequired property that returns True if it is being called from a thread that did not create the control. When True, you must create a pointer to the function that will access the control, switch to the thread that created the control, and use the pointer to call the function again.
In .NET, a pointer to a function is a Delegate. You'll declare a delegate that has the same function signature (parameters) as the event you want to handle. In this case, your delegate has the same signature as the Stopped event. Add this line of code before the Stopped event handler:
Delegate Sub myJobManagerDelegate(ByVal sender As Object, ByVal e As CogJobManagerActionEventArgs)
Now in the Stopped event handler, you'll check whether the handler is being called from the wrong thread. If it is, you'll use the delegate you defined to create a pointer to the handler, and then use the Invoke method to call it recursively. This is what the Stopped event handler should look like:
Private Sub myJobManager_Stopped(ByVal sender As Object, ByVal e As CogJobManagerActionEventArgs)
If InvokeRequired Then
Dim myDel As New myJobManagerDelegate(AddressOf myJobManager_Stopped)
Dim eventArgs() As Object = {sender, e}
Invoke(myDel, eventArgs)
Return
End If
RunOnceButton.Enabled = True
End SubThe Invoke method takes a pointer the the Stopped event handler and an object that consolidates the arguments to the handler.
This technique is a the standard way to handle the case in which a user interface item may be accessed by another thread. It is a good idea to learn this idiom.
If you run your program at this point, you will not get any errors. The next step is to add a display control so you can see what your program is doing.