When joining the vCampus team 2 weeks, I was looking for something simple to refresh my programming skills. It turned out that porting the PIAsynchStatus Example (see pisdk.chm) from VB6 to VB.Net was challenging enough. I believe the result is a good example for asynchronous PI Data Access. So please allow me using it for my first blog post even there will be nothing new for most of you.
The original example is using a Timer to check for status changes from time to time each 0.5 seconds). The advantage is that this allows checking the progress but my idea was using asynchronous callback instead of the Timer. So I have removed the timer and changed the definition of the routine that is called by the Timer in the original VB 6 example to make it handled (triggered) by the OnStatusChange event fired by the asynchronous GetPoints() call:
Private Sub asynchevents_OnStatusChange(ByVal NewStatus As CallStatusConstants)
Private Sub asynchevents_OnStatusChange(ByVal NewStatus As CallStatusConstants) Handles asynchevents.OnStatusChange
Updating a ProgressBar with OnProgressChange() event gave me an issue. The first OnProgressChange() was with 1% and the second with 10%. Afterwards my little application was hanging even after disabling the handler for OnStatusChange(). If you’ve managed using OnProgressChange() succesfully, please let me know how. I decided removing the ProgressBar for now.
The next issue I ran into is the following error when attempting to update a control on Form1 from within asynchevents_OnStatusChange():
InvalidOperationException was unhandled by user code: Cross-thread operation is not valid …
The callback from the asynchronous function call is handled in an additional thread that does not have access to the controls that are handled with the main application thread.
The solution is delegating control updates to a separate sub and invoking methods if needed. The OnStatusChange() sub handles different statuses and delegates control updates to separate subs:
Private Sub asynchevents_OnStatusChange(ByVal NewStatus As CallStatusConstants) Handles asynchevents.OnStatusChange Select Case asynchevents.Status Case Is = csInProgress ShowInProgress() Case Is = csComplete ShowComplete() Case Is = csCancelComplete ShowCancel() Case Else ShowElse() End Select End Sub
Let's have a look at ShowInProgress() and the conditional invoke.
Private Sub ShowInProgress() If Me.InvokeRequired Then Me.Invoke(New MethodInvoker(AddressOf ShowInProgress)) Else Try lbStatus.Items.Add("New Status: ... in progress") Catch ex As Exception lbStatus.Items.Add("ShowProgress: " & ex.Message) End Try End If End Sub
The complete Visual Studio .NET 2010 project is attached to this post. I am excited about your replies espacially about your suggestions for improvements.
Last but not least I like to discuss the where clause that is passed with the GetPoints() call. This is a powerful way searching tags by its attributes. Please review the following examples.
2. Search for tags that have a specific point source and a specific Location1 value. This query is very useful when one would retrieve all the tags serviced by a specific interface instance: 3. Query for all tags having a specific pointtype assigned:
pointsource='OPC' AND Location1=1
2. Search for tags that have a specific point source and a specific Location1 value. This query is very useful when one would retrieve all the tags serviced by a specific interface instance:
3. Query for all tags having a specific pointtype assigned: