Click or drag to resize
StaMaImplementing a Simple State Machine Application for .NET Windows Desktop Framework

Describes how to integrate a StaMa state machine into a .NET Windows Desktop Framework based application.

This step by step description shows how to create a simple console application that uses a StaMa state machine with two states and transitions between them.

The Microsoft Visual Studio project and the source code is also available in the release package at StaMa_State_Machine_Controller_Library\Samples\netfwk\SampleSimpleStateMachineNETFWK\SampleSimpleStateMachineNETFWK.csproj.

The following environment is assumed to be installed:

Newer or older versions of the above software will probably not affect the below steps as such, however references to files, paths and versions might be different.

Creating the Microsoft Visual Studio application project

  1. Open Microsoft Visual Studio.

    From the File menu select New, then Project.... The New Project dialog appears.

    In the New Project dialog select Templates / Visual C# / Windows Desktop / Console Application.

    Name the new solution and project SampleSimpleStateMachineNETFWK. Close the dialog and create the solution by pressing OK.

  2. Copy the following code into the Program.cs file:

    Program.cs
    using System;
    
    namespace SampleSimpleStateMachineNETFWK
    {
        class Program
        {
            [STAThread]
            static void Main(string[] args)
            {
                bool exit = false;
                while (!exit)
                {
                    DateTime startTime = DateTime.Now;
                    if (Console.KeyAvailable)
                    {
                        ConsoleKeyInfo key = Console.ReadKey(true);
                        switch (key.Key)
                        {
                            case ConsoleKey.E:
                                Console.WriteLine("{0} You pressed E!", DateTime.Now.ToString("HH:mm:ss.fff"));
                                break;
                            case ConsoleKey.X:
                            case ConsoleKey.Spacebar:
                            case ConsoleKey.Escape:
                                Console.WriteLine("{0} Closing application.", DateTime.Now.ToString("HH:mm:ss.fff"));
                                exit = true;
                                break;
                            default:
                                break;
                        }
                    }
                    else
                    {
                    }
                    System.Threading.Thread.Sleep(100); // Throttle CPU load.
                }
            }
        }
    }
  3. Compile the solution. No compiler errors appear.

  4. Execute the solution by selecting "Start Debugging" from the "Debug" menu or by pressing F5.

    The console application window appears.

    Press the E key on the keyboard. The application displays You pressed E!.

    Press the Space key on the keyboard. The application displays Closing application. with short duration and ends.

The above project provides a frame that allows to send events (keystrokes) to an application and handle them. The steps in the next section will add a simple state machine based on StaMa.

Adding the simple StaMa state machine.

  1. Add the assembly reference to StaMa.dll.

  2. Add a new class with file name SampleSimpleStateMachineNETFWK.cs to the project.

    Copy the following code into the SampleSimpleStateMachineNETFWK.cs file:

    SampleSimpleStateMachineNETFWK.cs
    using System;
    using StaMa;
    
    namespace SampleSimpleStateMachineNETFWK
    {
        class SampleSimpleStateMachineNETFWK
        {
            private StateMachine m_stateMachine;
            private DateTime m_state2Entered;
    
    
            public SampleSimpleStateMachineNETFWK()
            {
                StateMachineTemplate t = new StateMachineTemplate();
    
                //## Begin Structure
                // Generated from <file:S:\StaMa_State_Machine_Controller_Library\StaMaShapesMaster.vst> page "SampleSimpleStateMachineNETFWK"
                // at 07-22-2015 22:09:50 using StaMaShapes Version 2300
                t.Region("State1", false);
                    t.State("State1", EnterState1, ExitState1);
                        t.Transition("Transition1to2", "State2", "Event1", null, null);
                    t.EndState();
                    t.State("State2", EnterState2, ExitState2);
                        t.Transition("Transition2to1", "State1", null, IsState2Timeout, null);
                    t.EndState();
                t.EndRegion();
                //## End Structure
    
                m_stateMachine = t.CreateStateMachine();
                m_stateMachine.TraceStateChange = this.TraceStateChange;
    
                m_stateMachine.Startup();
            }
    
    
            public void Finish()
            {
                m_stateMachine.Finish();
            }
    
    
            public void KeyPressed(ConsoleKey key)
            {
                m_stateMachine.SendTriggerEvent("Event1");
            }
    
    
            public void CheckTimeouts()
            {
                m_stateMachine.SendTriggerEvent(null);
            }
    
    
            private void EnterState1(StateMachine stateMachine, object triggerEvent, EventArgs eventArgs)
            {
                Console.WriteLine("Called EnterState1");
            }
    
    
            private void ExitState1(StateMachine stateMachine, object triggerEvent, EventArgs eventArgs)
            {
                Console.WriteLine("Called ExitState1");
            }
    
    
            private void EnterState2(StateMachine stateMachine, object triggerEvent, EventArgs eventArgs)
            {
                Console.WriteLine("Called EnterState2");
                m_state2Entered = DateTime.Now;
            }
    
    
            private void ExitState2(StateMachine stateMachine, object triggerEvent, EventArgs eventArgs)
            {
                Console.WriteLine("Called ExitState2");
            }
    
    
            private bool IsState2Timeout(StateMachine stateMachine, object triggerEvent, EventArgs eventArgs)
            {
                return DateTime.Now - m_state2Entered > new TimeSpan(0, 0, 0, 2);
            }
    
    
            private void TraceStateChange(StateMachine stateMachine,
                                          StateConfiguration stateConfigurationFrom,
                                          StateConfiguration stateConfigurationTo,
                                          Transition transition)
            {
                Console.WriteLine("{0} ActiveState={1} entered through Transition={2}",
                                  DateTime.Now.ToString("HH:mm:ss.fff"),
                                  stateConfigurationTo.ToString(),
                                  (transition != null) ? transition.Name : "Startup/Finish");
            }
        }
    }

    The above code adds a state machine with two states "State1" and "State2", a transition "Transition1to2" from "State1" to "State2" which is triggered through signal "Event1" and a transition "Transition2to1" from "State2" to "State1" which is active when the timeout for the transition elapsed. The timeout is represented through the transition guard condition.

    "State1" has an entry action EnterState1 and an exit action ExitState1 and "State2" has an entry action EnterState2 and an exit action ExitState2. These are executed when the state machine switches the state from "State1" to "State2" or back from "State2" to "State1" .

    The KeyPressed method sends the "Event1" signal to the state machine which executes the "Transition1to2" when the state machine is in state "State1".

    The CheckTimeouts method sends the null signal to the state machine which causes that transitions with only a transition guard condition are checked. This causes "Transition2to1" to be executed when the state machine is in state "State2" and the guard condition returns true.

  3. Extend the Program.cs file to invoke the methods of the SampleSimpleStateMachineNETFWK class:

    Create a new SampleSimpleStateMachineNETFWK instance at the beginning of the Main method.

    Invoke the SampleSimpleStateMachineNETFWK.KeyPressed method from within in the case ConsoleKey.E: branch.

    Invoke the SampleSimpleStateMachineNETFWK.CheckTimeouts method when no key is pressed (Console.KeyAvailable returning false).

    Invoke the SampleSimpleStateMachineNETFWK.Finish method from within in the case ConsoleKey.X: branch.

    The code should now look similar to this:

    Program.cs
    using System;
    
    namespace SampleSimpleStateMachineNETFWK
    {
        class Program
        {
            [STAThread]
            static void Main(string[] args)
            {
                Console.WriteLine("Press E to trigger the transition from State1 to State2.");
                Console.WriteLine("Expect 2 seconds delay for timeout transition from State2 to State1.");
                Console.WriteLine("Press X or Space or ESC to exit.");
    
                SampleSimpleStateMachineNETFWK stateMachine = new SampleSimpleStateMachineNETFWK();
    
                bool exit = false;
                while (!exit)
                {
                    DateTime startTime = DateTime.Now;
                    if (Console.KeyAvailable)
                    {
                        ConsoleKeyInfo key = Console.ReadKey(true);
                        switch (key.Key)
                        {
                            case ConsoleKey.E:
                                Console.WriteLine("{0} You pressed E!", DateTime.Now.ToString("HH:mm:ss.fff"));
                                stateMachine.KeyPressed(key.Key);
                                break;
                            case ConsoleKey.X:
                            case ConsoleKey.Spacebar:
                            case ConsoleKey.Escape:
                                Console.WriteLine("{0} Closing application.", DateTime.Now.ToString("HH:mm:ss.fff"));
                                stateMachine.Finish();
                                exit = true;
                                break;
                            default:
                                break;
                        }
                    }
                    else
                    {
                        stateMachine.CheckTimeouts();
                    }
                    System.Threading.Thread.Sleep(100); // Throttle CPU load.
                }
            }
        }
    }
  4. Set a breakpoint at the end of method SampleSimpleStateMachineNETFWK.TraceStateChange and start the debugger e.g. by pressing F5.

    Press the E key on the keyboard, then press the Space key.

    The breakpoint in SampleSimpleStateMachineNETFWK.TraceStateChange is hit (four times):

    1. During startup when the state machine enters its initial state.

    2. Triggered through "Transition1to2" when the state machine transitions from "State1" to "State2" in response to the signal "Event1".

    3. Triggered through "Transition2to1" when the state machine transitions from "State2" to "State1" in response to the timeout.

    4. Finally when the application is ended.

The above code provides a minimal executable state machine that can be extended with composite states or orthogonal sub-regions.