Background Operations using the COM version
It is often useful to perform operation in the background, in order to keep a responsive user interface, and this is possible in DicomObjects using an asynchronous DicomConnection object.
- Note: Asynchronous in this sense refers to how the object interacts with your application, and has no connection to DICOM Asynchronous communications (which no-one ever uses!)
In order to manage asynchronous operations, they must be performed using a DicomConnection object, which must be created using the New("DicomConnection") method of either a DicomViewer or a DicomServer, and not using New DicomConnection. The reason for this is simply to link to a static object to which the ActionComplete can be attached!
The capabilities of a DicomConnectin object in DicomObjects are written in such a way that it is possible to write a full multi-threaded application from a single threaded environment. In order to achieve this however, it is necessary to follow some rules. The important point to remember is that a DicomConnection, even when in asynchronous mode can only have a single outstanding operation, so any further operations will cause the calling thread to wait until the previous operations have completed. This is best shown by an example, where Connection is a DicomConnection created as above
When this code is executed, the SendImages method will return immediately, and transfer of the images on the established association will commence. However, the SendStatus method cannot return until the operations initiated by the previous method have completed, and this may be a long time, during which the application would be unresponsive. To avoid this issue, each operation should be initiated only once the previous one has completed, and the best way of doing this is to use the ActionComplete event. Using this approach, only the very first operation is triggered from with the original initiating event (such as the user pressing the "send" button), and all other operations are called from the ActionComplete event. This is shown in the following pseudo-code:
Main initiating routine:
Set Connection = Viewer.New("DicomConnection") Connection.SetDestination(…) [no operations on the Connection object here!] return
The Viewer's ActionComplete event:
Viewer.ActionComplete(connection,…) if success then case(Action) "SetDestination": [locate and load images to send] connection.SendImages(…) break "SendImages": connection.SendStatus(0) connection.Close break end case end if
For the best asynchronous behaviour, SendImages should where possible be passed a string or array of strings, being the filenames of the files to be sent, as this causes the files to be loaded on the background thread, further reducing delays on the main thread.
Although not used in the above simplistic example, there will often be occasions where the routine initiating an asynchronous method needs to pass some data or context information on to the ActionComplete event, to ensure that subsequent operations are appropriate. The Tag property is designed for this purpose. Note that the value passed to the ActionComplete event is the value at the time that the initiating method is called, so Tag should be set before making any such calls.