Using OpenSpan Adapters in a C# project
Written by Paul Guiheen   
Friday, 05 March 2010 19:57

Although the ‘Code common to all projects’ comes first you may need to look at the ‘References you’ll need to add’ in the following two sections to get the first section working.

The examples in this doc all use a C# Windows Application as the C# project.

They use this Win Form to set up the OpenSpan objects, i.e. when the Win Form loads, the OpenSpan objects are created, listeners are added to adapter controls, etc.

The Win Form is not required, it’s just an easy way to put a sample together.

Code common to most projects

The following code is from a solution with an OpenSpan project and a C# Win Form project. The OpenSpan project contains a Windows App called ‘Calc’, and the C# project has a Win Form called ‘Form1’.

When the Win Form is being created a Calc object is also created.

public partial class Form1 : Form
{
private Calc mCalc; // 'Calc' Windows App from the OpenSpan project

public Form1()
{
InitializeComponent();
mCalc = new Calc(); // create a Calc object
}

Now when the Win Form is created, the Calc object is ready to be used.

Register listeners for OpenSpan adapter events

This is not needed in all projects but is common.

The following code shows the event handler called when the Win Form loads.

private void Form1_Load(object sender, EventArgs e)
{
// listen for anyone clicking button ‘7’ on Calc
mCalc.btn7.Click += new EventHandler(btn7_Click);
}

void btn7_Click(object sender, EventArgs e)
{
// this method will be called when someone clicks button ‘7’
}

 

Start the object and marshal it's events to the WinForm thread

If you try to update your Win Form from any other thread except the UI thread you are risking unstable behaviour such as creating a deadlock.

E.g. your Win Form is waiting for the OpenSpan adapter to do something, but at the same time the OpenSpan adapter is trying to set the Text of a label on the Win Form.

Both threads end up waiting for each other to finish, and you have to kill the runtime.

To prevent this, you need to marshal the OpenSpan adapter events to the UI thread. Now all Win Form updates, even those initiated by an OpenSpan adapter, happen on the UI thread and instability is avoided.

The exception to this rule is when you have a process which takes a long time to complete. E.g. an OpenSpan adapter event fires an automation that runs complex database searches, then sorts and filters the data, and then updates a DataGridView on the Win Form. In this case you do not want your Win Form to have to wait for the automation to complete as the Win Form will be unresponsive while it waits.

The following code shows the event handler called when the Win Form loads. The ‘Calc’ adapter is started and its events are marshaled to the UI thread.

private void Form1_Load(object sender, EventArgs e)
{
// create a delegate for the method used to start 'Calc'
MethodInvoker startCalc = StartCalc;

// execute the delegate asynchronously so that if you are
// starting multiple adapters they will not interfere with
// each other (a situation called a race condition)
startCalc.BeginInvoke(null, null);
}

void StartCalc()
{
// Start(ISynchronizeInvoke syncObject)
mCalc.Start(this); // this Win Form is the syncObject and so
} // Calc events are marshaled to the UI thread

Now any events fired by the OpenSpan adapter that update the Win Form can do so without risking unstable behaviour.

Events from the adapter object itself (Started, Stopped, Starting, Stopping, Terminated, WindowCreated, etc ) will not be synchronized. Control events will still be synchhronized. The most common cases for cross-thread problems are the control events.

This approach will be revisited for GA and the Start/Stop events will probably be synchronized then. The window and process events are really for internal use so probably can’t be synchronized. Some Text Adapter events may need to be synchronized as well.

 

Using automations in code

 

References you’ll need to add

  • The project containing the automation(s)
  • OpenSpan.Runtime.dll
  • OpenSpan.Automation.dll – gives you access to InvokeEntryPoint(), etc.
  • OpenSpan.dll – required by OpenSpan

When MSBuild is supported you will no longer have to add these References as they are already added in the OpenSpan project, and so when you add a reference to the OpenSpan project the references will be automatically added for you.

Code snippet

The following code is from the click handler of a button on a C# windows form.

When the button is clicked the following automation is called. It is passed the two string values in the win form textboxes and the win form label will display the result passed back from the exit point.

The following code has each operation split out into its own line to make it more readable.

The “os_Project” object in the code below is instantiated elsewhere in the class and it is an OpenSpan project object. This project is the one containing the above automation, i.e. the project you added a reference to.

private void btn_Call_Click(object sender, EventArgs e)
{
// the two textfield values
String param1 = txt_String1.Text;
String param2 = txt_String2.Text;

// call the autx - pass it the strings - get an object in return
object returned;
returned = os_Project.Automation1.InvokeEntryPoint(param1, param2);

// convert the returned object to an integer
int result = Convert.ToInt32(returned);

// convert the int to a string and write it to the win form label
lbl_Result.Text = result.ToString();
}

 

Using Adapters in code

References you’ll need to add

  • The project containing the adapter(s)
  • OpenSpan.Adapters.dll
  • OpenSpan.Adapters.Windows.dll – gives access to adapter members e.g. Start( )
  • OpenSpan.dll – required by OpenSpan

When MSBuild is supported you will no longer have to add these References as they are already added in the OpenSpan project, and so when you add a reference to that project the references will be automatically added for you.

Code snippet


using OpenSpan29;

public partial class Form1 : Form
{
private Calc mCalc; // declare your calc object

public Form1()
{
InitializeComponent();

// create a calc object
mCalc = new Calc();

// start the calc adapter
MethodInvoker startCalc = StartCalc;
startCalc.BeginInvoke(null, null);
}

void StartCalc()
{
// marshal adapter events to the UI thread
mCalc.Start(this);
}

private void Form1_Load(object sender, EventArgs e)
{
// listen for clicks on button 7
mCalc.btn7.Click += new EventHandler(btn7_Click);
}

void btn7_Click(object sender, EventArgs e)
{
// display a message when button 7 is clicked
MessageBox.Show("button 7 was clicked");
}
}

 

In the above code there is a using OpenSpan29; statement.

This makes the code more readable as you can now refer to the Calc project item as Calc instead of its full name OpenSpan29.Calc.

What’s happening in the code;

  1. When the win form is created a calc object is also created and the calc adapter is started.
  2. When the win form is loaded a listener is registered to listen for click events on calc button 7.
  3. When button 7 is clicked a message box displays.

The Win Form in this project doesn’t have any UI controls on it – it is only there to fire events in whose handlers we can execute code to get the calc adapter set up.

Troubleshooting


You add an adapter to your OpenSpan project but when you go back to your C# project you don’t see it in the code prompt and when you type its name it is underlined in red

You need to build your OpenSpan project after you make changes to it or the changes will not be visible in you C# project

You run your project and see the OpenSpan adapter but not the C# Win Form

You need to set your C# project as the StartUp Project.

Also if you are going to start your adapter in code you may want to set it to StartOnProjectStart = False in the OpenSpan project.

You copy the event handler code from this doc and paste it into your C# Win Form but it doesn’t work

C# Win Form events are coded in 2 places, Form1.cs and also Form1.Designer.cs. If you double click a win form button it’ll automatically add the click event for you in both these places. You can then see what is required and write similar code for whatever other win form events you are interested in.

The following code is an example of how the Win Form Load event is coded in Form1.Designer.cs

this.Load += new System.EventHandler(this.Form1_Load);

You can’t tell if your method is being called or not

The following code displays a message dialog, add it to the method and see if it displays

MessageBox.Show("method was called");

You have an OpenSpan automation with multiple Exit Points but you can’t tell which one the automation ends at

You have a Win Form in your OpenSpan project that you used to test your automations work as expected. You set the Win Form to DoNotRun = True but when you run your C# project the OpenSpan win form still runs.

This is As Designed - Run/Not Settings are included in packages only. Since C# apps just import the dll (not a package), there is no way to apply these settings

You want to use OpenSpan toolbox components in your C# project

You need to add a reference to OpenSpan.Automations.dll to be able to access the Global Container. You need to add a reference to OpenSpan.Controls.dll to be able to access component members.