Article

Technical Article: Starting Adapters and Multithreading

This article discusses both how to start an adapter and multithreading. While these seem like separate issues, in fact how you start your application affects how it works with events.

A Studio adapter is a class generated by the Studio tools which encapsulates the data in an application and permits your code to monitor and modify how the application works.

Starting an adapter from .NET

There are a few ways to start an adapter from a .NET project. The simplest is to use the adapter’s Start() method.

// Starts the external application
Crm.Start();
}

The Start() method can also take a parameter which provides a synchronization object. This object must implement the ISynchronizeInvoke interface. In practical terms, you pass it a Windows form UI object such as a form or a control. Doing this lets the adapters automatically marshal their events to your UI, so you do not have to. This is because in Windows, you cannot modify a UI element safely except from the thread the UI element was created on.

You only need to do this for adapters which you handle events from and that the event handlers modify UI items. If either of those conditions are not true, then you do not need to pass an object to the Start() method.

// Starts the external application
Crm.Start( <strong>this </strong>); // <strong><em>this</em></strong> is a System.Windows.Forms.Form object
}

Multithreading with adapters and .NET

If you start your application adapter with the Start() method and no synchronization, you will then need to handle marshalling events explicitly. This has the advantage of giving your code more control over how it is done, with the disadvantage of you must remember to do this or else you will likely have exceptions thrown while your application is running.

Microsoft Windows requires that all changes made to a user interface control be done by the thread that created the control. This is simply how Win32 works. It is, however, something you need to be aware of since it will happen when handling events from external application adapters.

Studio adapters will fire their events on different threads than your .Net applications UI thread. This keeps your application’s UI responsive however it also means that you need to marshal events to the UI thread to work with controls like text boxes and labels. If you do not do this, you will get cross-threading exceptions.

This is not needed if your event handler does not touch a UI control or if you do not handle events from the application.

Advantages and disadvantages of each method

Start( this ) -- This technique is easy and safe. You do not need to worry about when to marshal code. Usually you have a System.Windows.Forms.Form object that you can pass to the Start() method as a this object and it will then correctly marshal all events for you.

The disadvantage is that when your code is in an event handler, it will be on the thread of the UI object and the UI object will not handle any repaint or other events until your code is done. This is only an issue if your code takes a long time to complete. This is no different from the usual event handlers in .NET code. In these cases where it does take a long time, you can place calls to the Update() method in your code to force a repaint or call the message loop, the Application.DoEvents() method, or you can spin off a different thread to handle the processing. Normally though, this is not an issue.

One thing to note, is that all control events are marshaled for you. However, at this time, adapter events (Starting, Stopping, Stopped) are not marshaled and you still need to use Invoke() if you use these events and modify a UI while handling the event.

Start() -- You have more control with this method of starting an adapter, but you must use the Invoke() method to marshal UI references to the correct thread.

The advantage is more control, the disadvantage is you need to be more careful when coding and debugging. Also, same problem of long running events can still happen if you marshal the code to the UI thread and then take a long time in that thread.

How to marshal events in your code

This only applies if you use the Start() method without giving it an object reference to synchronize with.

The following is a sample pattern for handling an UI control safely from different threads. There are many patterns you can use; this one is self-contained. You can find out more by searching the Microsoft Developer Network (MSDN). For instance, see this article for more information:

http://blogs.msdn.com/csharpfaq/archive/2004/03/17/91685.aspx

The important thing is to use the Invoke() method when updating anything on a UI control. Some examples are changing Text, clearing a list box, or working with a DataGridView. If you use the Invoke() method, you will need to use a delegate. The example below shows a delegate for passing a single string argument.

public delegate void updateUI( string key );

///


/// Handles updating the application bar's values. It’s done here so we can ensure its
/// thread safe for calls from the OpenSpan adapter.
///
/// account number for the window we are working with
public void handleToolbarUpdate( string keyText )
{
if ( InvokeRequired )
{
// Call self but on the correct thread
Invoke( new updateUI( handleToolbarUpdate ), keyText );
return;
}

… the rest of your code …

If, however, you do not need to pass arguments, then you can use the MethodInvoker delegate which is part of .NET such as:

if ( InvokeRequired )
{
Invoke( new <strong>MethodInvoker</strong>( updateLabels ) );
return;
}

Published December 6, 2016 — Updated March 29, 2017


100% found this useful

Have a question? Get answers now.

Visit the Pega Support Community to ask questions, engage in discussions, and help others.