Streamlined Version V2

If we take a look at the flow diagram of version one we see that the feature complete version mixes some data flows. The diagram isn’t easy to understand because of the number of the related components. Data flows are not separated by processes. In this version we redesign the application to improve the readability of the diagrams. Of course this is not absolutely necessary for our “trivial” application but is done to explain how to enable you to design much more complex applications.

Our application consists of four processes (called flows in this context): the start of the clock, to show the current time, to start the alarm clock and to set off the alarm. These are the four data flows we try to design now. The following diagram shows this variation of the application:

AD4.AlarmClockSample.V2.png

The first flow to start the clock is called “StartClockFlow”. Involved components are the UI and the TimerClock. Converted to the AD4 application description language the following script shows the result:

$App Settings {
    $CodeGeneration {
        BinFolder = "..\..\AD4.AlarmClockSample.bin\Debug\"
        BinIncludeSubFolder = "True"
        CodeFolder = "..\..\AD4.AlarmClock\"
    }
}

$Flow StartClockFlow {
    $Step MainWindow { CustomName = "UI" PreparedInstance = "True" }    
    $Wire UI?StartTimerClock -> TimerClock
}

To show the current time we add the next flow with name “ShowCurrentTimeFlow” in the same way:

$App Settings {
    $CodeGeneration {
        BinFolder = "..\..\AD4.AlarmClockSample.bin\Debug\"
        BinIncludeSubFolder = "True"
        CodeFolder = "..\..\AD4.AlarmClock\"
    }
}

$Flow StartClockFlow {
    $Step MainWindow { CustomName = "UI" PreparedInstance = "True" }    
    $Wire UI?StartTimerClock -> TimerClock
}

$Flow ShowCurrentTimeFlow {
    $Step MainWindow { CustomName = "UI" PreparedInstance = "True" }
    $Wire TimerClock -> UI?CurrentTime
}

As you see in this snippet, the declaration of the UI component (of type MainWindow) is declared twice. Also, the component “TimerClock” is used twice. By default each flow is designed to use seperate instances of involved components. This would cause a mistake in our application! There’s only one instance of the UI used everywhere. The component “TimerClock” is a stateful component (implicit state not sending current time, implicit state sending current time). The instance of the second flow would create an own instance of “TimerClock” that is in a wrong state.

One possibility to handle this issue is to declare a functional unit as single instance. Therefore, the same instance is used in every flow. The section to define these “special” instances is also called “GlobalStepDefinitions”. Applied to our sample the following snippet shows the result of this feature:

$App Settings {
    $CodeGeneration {
        BinFolder = "..\..\AD4.AlarmClockSample.bin\Debug\"
        BinIncludeSubFolder = "True"
        CodeFolder = "..\..\AD4.AlarmClock\"
    }
}

$App GlobalStepDefinitions {
    $Step MainWindow { CustomName = "UI" PreparedInstance = "True" SingleInstance = "True" }
    $Step TimerClock { SingleInstance = "True" }
}

$Flow StartClockFlow {
    $Wire UI?StartTimerClock -> TimerClock
}

$Flow ShowCurrentTimeFlow {
    $Wire TimerClock -> UI?CurrentTime
}

This leads us to the deduction (Thank you Sherlock Holmes ;-): Avoid stateful components if possible! Stateless components never produce these problems. If you have to use a stateful component, try to define these as single instances if possible. Otherwise, you have to “inject” the right instance as a prepared instance at the right flow class as explained before.

The third flow is called “SetAlarmTimeFlow”. The “CalculateRemainTime” component is stateful too. Therefore we add this component to the “GlobalStepDefinitions” section also:

$App Settings {
    $CodeGeneration {
        BinFolder = "..\..\AD4.AlarmClockSample.bin\Debug\"
        BinIncludeSubFolder = "True"
        CodeFolder = "..\..\AD4.AlarmClock\"
    }
}

$App GlobalStepDefinitions {
    $Step MainWindow { CustomName = "UI" PreparedInstance = "True" SingleInstance = "True" }
    $Step TimerClock { SingleInstance = "True" }
    $Step CalculateRemainTime { SingleInstance = "True" }
}

$Flow StartClockFlow {
    $Wire UI?StartTimerClock -> TimerClock
}

$Flow ShowCurrentTimeFlow {
    $Wire TimerClock -> UI?CurrentTime
}

$Flow SetAlarmTimeFlow {
    $Wire UI?AlarmDuration -> ConvertToDouble?StringInputPin
    $Wire ConvertToDouble -> CalculateAlarmTime
    $Wire CalculateAlarmTime -> CalculateRemainTime?AlarmTime
}

The last flow is called „RaiseAlarmFlow“ with many involved components:

$App Settings {
    $CodeGeneration {
        BinFolder = "..\..\AD4.AlarmClockSample.bin\Debug\"
        BinIncludeSubFolder = "True"
        CodeFolder = "..\..\AD4.AlarmClock\"
    }
}

$App GlobalStepDefinitions {
    $Step MainWindow { CustomName = "UI" PreparedInstance = "True" SingleInstance = "True" }
    $Step TimerClock { SingleInstance = "True" }
    $Step CalculateRemainTime { SingleInstance = "True" }
}

$Flow StartClockFlow {
    $Wire UI?StartTimerClock -> TimerClock
}

$Flow ShowCurrentTimeFlow {
    $Wire TimerClock -> UI?CurrentTime
}

$Flow SetAlarmTimeFlow {
    $Wire UI?AlarmDuration -> ConvertToDouble?StringInputPin
    $Wire ConvertToDouble -> CalculateAlarmTime
    $Wire CalculateAlarmTime -> CalculateRemainTime?AlarmTime
}

$Flow RaiseAlarmFlow {
    $Wire TimerClock -> CalculateRemainTime?CurrentTime
    $Wire CalculateRemainTime -> DecideToRaiseAlarm
    $Wire DecideToRaiseAlarm -> SpecifyAlarmString
    $Wire SpecifyAlarmString -> UI?AlarmText
}

Finally we have to customize the “Application_StartUp” routine. The injection of the UI instance is a little bit different because we defined the UI as single instance. All single instances are handled in a special way by the AppBuilder class. Flow classes that use single instances take the reference from the AppBuilder.SingleInstances sub class. We have to inject the prepared instance there. The following code snippet shows the customized code:

/// <summary>Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
	private void Application_Startup(object sender, StartupEventArgs e)
	{
		//Based on: http://www.c-sharpcorner.com/uploadfile/mahesh/show-multiple-windows-at-startup-in-wpf/ 
		StartWindow tStartWindow = new StartWindow();
		tStartWindow.Show();
 
		AD4.AlarmClockFrontEnd.MainWindow tMainWindow = 
			new AlarmClockFrontEnd.MainWindow();
 
		AD4.AppDesignerGeneration4Code.AppBuilder tAppBuilder = 
			new AppDesignerGeneration4Code.AppBuilder();

		tAppBuilder.SingleInstances.UIInstance = tMainWindow;
		tAppBuilder.BuildApp(null, null);

		tStartWindow.Close();
		tMainWindow.ShowDialog();
		Shutdown();
	}
}

Note:
You can download the latest version of the solution here: AD4.TutorialSamples

Update (2014-08-13): Design attributes extended:
AD4.Tutorial.02.RaiseAlarmFlow.23.27.png
AD4.Tutorial.02.SetAlarmTimeFlow.23.27.png
AD4.Tutorial.02.ShowCurrentTimeFlow.23.27.png
AD4.Tutorial.02.StartClockFlow.23.27.png
Update (2015-03-30): This page is obsolete. You find the current version of the tutorial as offline documentation included in downloads...

Previous: Feature Complete Version V1
Next: Flows & Pins (Version V3)

Last edited Mar 30, 2015 at 9:17 AM by InneHo, version 11