Amethyst Tutorials

Back to -Tutorials -Amethyst Tutorials

Using Flash In .NET - channels of communication

How to send commands and data between C# and ActionScript

In another tutorial I explained how to create a Visual Studio Solution containing both a Flex (or Flash) project and a .NET project. The output (SWF) of the Flex project was then embedded into the .NET application. This time I want to explain how to open channels of communication between .NET and Flash so that you can send commands and data from one to the other. You can download the source code of this project for Visual Studio 2010 and try it for yourself.

This Solution contains a development of the simple Flex 4 ‘exploring’ game which I used in my last example. As before, a C# application contains the Flex 4 SWF on a form. But this time there is a big difference. In my earlier version, all the interesting stuff happened in the Flex 4 program – it contained both the buttons to let the player move in four compass directions plus a text area to display details of the current location. In this new version the .NET form contains all the buttons while the Flex program hosts the text area to display the descriptions. When I click a button I will pass information from .NET to Flex indicating the direction in which to move the player. When the player has moved, the Flex program will send the name of the new room back to .NET so that it can be displayed on the form.

In the code editor you see C# code (top) and ActionScript (bottom). The C# code calls the ActionScript ExecCommand() method so that the .NET buttons on the form can send commands to the Flex control (everything inside the white box) embedded into the form.

To do this I need to open up a two-way channel of communication between the Flex component and the .NET application that contains it. Let’s see how this is done.

Call Flash From .NET

As explained in my previous tutorial, I’ve added my Flex SWF to my .NET form. In the form constructor of the C# code of Form1.cs I’ve specified a delegate method, onFlashCall, which will execute when a call is received from the SWF (we’ll come back to this later):

flashDisplay.FlashCall += onFlashCall;

When a button is clicked it sends a string such as “NORTH” or “SOUTH” to my movePlayer() function. This string is assigned to the aDir argument (see below). My code creates an XML-format string containing aDir between <string></string> tags to indicate its type. The first part of the string also contains a method name (specified after invoke name=) Here the name I’ve chosen is ExecCommand and, as we shall see, this name has to match the name of a method defined in the ActionScript of my Flex program. Once the string has been constructed it is passed to the SWF using the SWF component’s CallFunction() method which may (optionally) return a string, which is here assigned to the callStatus variable:

private void movePlayer( String aDir ) {
  StringBuilder sb;
  string callStatus;
  try {
     sb = new StringBuilder();
     sb.Append(@"<invoke name=""");
     sb.Append("ExecCommand");
     sb.Append(@""" returntype=""xml""><arguments>");
     sb.Append("<string>"+aDir+"</string>");
     sb.Append("</arguments></invoke>");
     callStatus = flashDisplay.CallFunction(sb.ToString());
  } catch( Exception ex ) {
     MessageBox.Show(ex.Message);
  }
}

Now turn to the ActionScript code in Wombat.designer.as. In the initGame() method which is called on applicationComplete (that is, after the SWF has loaded – an event-handler method to respond to applicationComplete is assigned in the Application tag in Wombat.mxml) you will see this:

ExternalInterface.addCallback( "ExecCommand", ExecCommand );

ExternalInterface is a class supplied by Flash and its addCallback method registers a function as ‘callable’ from the container hosting the SWF – which, in this case, is my .NET form. ExternalInterface.addCallback takes two arguments, the first (here "ExecCommand") is a string which is passed from the container and represents the function name to be called in ActionScript. The second (here, ExecCommand) is the actual function identifier. This identifier must match the name of a function in the ActionScript code. This is the function which I’ve written:

private function ExecCommand( aCommand : String ) : String {
  var status:String;
  ta.text = "Command received: [" + aCommand +"]";
  switch( aCommand ) {
     case "NORTH":
     case "SOUTH":
     case "WEST":
     case "EAST":
        moveTo( aCommand );
        status = "ok";
        break;
     default:
        status = "Unknown Command";
        break;
  }
  ExternalInterface.call( "Room", here._name );
  return status;
}

Notice that this takes an argument even though no arguments have been specified in the ActionScript code that designated this as a callback function. You may, in fact, pass zero, one or more arguments to a callback function. The important thing is that the function which receives these arguments (such as my ActionScript ExecCommand function) matches in number and type the arguments that are sent to it from the container. Here, these are the arguments defined in the XML-formatted string passed from my C# movePlayer() function:

"<string>"+aDir+"</string>"

Once ExecCommand() has received a string – such as “NORTH” – passed to it from the C# program, it just calls another method (moveTo) to move the player. It returns the string “ok” to the calling (C#) code or, if the received string is not a known command, it returns the string “Unknown Command”. This returned string is assigned to the callStatus variable in the C# code that called the ExecCommand function:

callStatus = flashDisplay.CallFunction(sb.ToString());

Call .NET From Flash

So far, the communication has all gone in one direction: C# issues calls to which ActionScript responds. There may be other occasions when you want to communicate in the other direction by calling C# from ActionScript. For example, when the player has moved to a new location, I want to pass back the name of the new room so that it can be displayed on my .NET form. To do that I use the call method of ExternalInterface like this:

ExternalInterface.call( "onFlashCall", here._name );

This is received by the onFlashClass method in my C# code (remember I designated this as the callback method earlier (flashDisplay.FlashCall += onFlashCall). Two pieces of information are passed by this method. The first argument is the name of the C# method to be called and the second is the data to be passed (but there may be more arguments if you wish).

According to Adobe’s documentation, the first argument is the “The alphanumeric name of the function to call in the container”. In fact, this is only really necessary when SWFs are embedded into web pages (the documentation also states “If the container is an HTML page, this method invokes a JavaScript function in a script element.”). The ‘function name’ argument is not required here. Instead, I have explicitly designated a delegate method in my C# code and that method would be called even if I wrote this in ActionScript (where null replaces a function name):

ExternalInterface.call( null, here._name );

However, for the sake of consistency and clarity I’ll stick to Adobe’s recommendation and use the C# method name as an argument. And this is the code of the delegated method in C#:

private void onFlashCall( object sender, AxShockwaveFlashObjects._IShockwaveFlashEvents_FlashCallEvent e ) {      
  XmlDocument doc = new XmlDocument();
  doc.LoadXml(e.request);
  XmlNode root = doc.FirstChild;
  roomNameTB.Text = root.FirstChild.InnerText;
}

This method receives the data passed from Flash in the request property of the event, e. The data is XML-formatted and the data item that is of interest to us is contained within a tag defining its type like this: <string>dataitem</string>. I extract the string itself as the InnerText of the FirstChild element. Then I simply display it in a text field on my form.

So that, in brief, provides a simple example of writing an application whose main user interface is a .NET form which communicates bidirectionally with an SWF component on the form.

Debugging Between .NET and Flash Platform Applications

Amethyst’s unique debugging capabilities let you step through both the programs (C# and ActionScript) in a single debugging session.

Amethyst’s unique ‘Cylon’ debugger gives you the ability to debug.NET and Flash Platform programs simultaneously. In this case I can put breakpoints in both my C# (top) and ActionScript (bottom) code and step from one to the other in a single debugging session.

The video below gives an example of using the Amethyst Cylon Debugger with the solution created in the tutorial above...

Bookmark and Share   Keywords:  .NET  Amethyst  tutorial

sample code  
flex-net-adventuregame-2.zip

VS2010 Solution containing C# and Flex (Amethyst) projects


32.1 kb
© SapphireSteel Software 2014