Coding along, doing more faster with WPF and ECO and OCL

My kid, Simon, is eight years old and we are in Thailand during the October break in School. He got a lot of homework to do while we are away – mostly Math – and does he need it… I have apparently not paid enough attention to his schooling – he (currently) sucks at math.

So being in Thailand I need to spend minimum time to hack up a Math-practice program to keep him busy. Some of your smartheads may say that this is exactly the problem; me turning to the computer rather than to just help my son with the math… I agree – I did/do help him the simple way too…

Simon Karlsen at Kho Samet

This is what I did:

image The important class is the abstract Calculation:

UML Derived attributes ECO 

It has only 3 persisted attributes, A B and Answer.

Then it has some OCL derived attributes, some that are overridden in each sub-class – one sub-class per type of test.

The implementation of “Correct” for the Addition2-sub-class: self.answer=A+B

And for Multiplication: self.answer=A*B

The Presentation attribute for Addition2: A.asString+’ + ‘ + B.asstring+’ = ‘

The Presentation attribute for Multiplication: A.asString+’ * ‘ + B.asstring+’ = ‘

UML Derived attributes ECO 

The Done attribute is not overriden and thus same for all tests: not self.Answer.isnull

Same for the BackColor attribute:

if (self.Correct) then
‘green’
else
  if (self.Done) then
    ‘red’
  else
    ‘grey’
  endif
endif

I implemented a method to init each test:

Code Snippet
  1. public override void InitValues()
  2. {
  3.     A = Session.GetRandom(2, 4);
  4.     B = Session.GetRandom(0, 11);
  5.  
  6. }

I decided to use a WPF UI and bind straight to the domain objects – no viewmodels.

 

Code Snippet
  1. <Window x:Class="EcoProjectMathPractice.Window1"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     Title="Simons matte övning"
  5.         xmlns:viewmodel="clr-namespace:Eco.ViewModel.WPF;assembly=Eco.WPF"
  6.         xmlns:eco="clr-namespace:EcoProjectMathPractice;assembly=EcoProjectMathPractice.EcoSpace"
  7.         xmlns:src="clr-namespace:EcoProjectMathPractice"
  8.         >
  9.     <Window.Resources>
  10.         <src:MyConverter x:Key="MyConverter"/>
  11.         <DataTemplate x:Key="RowTemplate">
  12.             <Grid Background="{Binding Path=BackColor,Converter={StaticResource MyConverter}}">
  13.                 <Grid.ColumnDefinitions>
  14.                     <ColumnDefinition Width="300"></ColumnDefinition>
  15.                     <ColumnDefinition Width="100"></ColumnDefinition>
  16.                     <ColumnDefinition Width="200"></ColumnDefinition>
  17.                 </Grid.ColumnDefinitions>
  18.                 <TextBlock Grid.Column="0" Text="{Binding Path=Presentation}"
  19.                 <TextBox Grid.Column="1" Text="{Binding Path=Answer}" FontSize="36"
  20.             </Grid>
  21.         </DataTemplate>
  22.     </Window.Resources>
  23.     <Grid>
  24.         <StackPanel   VerticalAlignment="Top" x:Name="Main">
  25.             <TextBlock Text="Matte Övning" FontSize="72" FontFamily="Planet Benson 2"
  26.             <StackPanel Orientation="Horizontal">
  27.                 <Button Click="Button_Click">
  28.                     <TextBlock Text="New session addition" ></TextBlock>
  29.                 </Button>
  30.                 <Button Click="Button_Click_1">
  31.                     <TextBlock Text="New session substraction" ></TextBlock>
  32.                 </Button>
  33.                 <Button Click="Button_Click_2">
  34.                     <TextBlock Text="New session multiplication" ></TextBlock>
  35.                 </Button>
  36.             </StackPanel>
  37.             <StackPanel Orientation="Horizontal">
  38.                 <ProgressBar Height="20" Width="400" Maximum="100"
  39.                 <TextBlock Text=" Number correct: "></TextBlock>
  40.                 <TextBlock Text="{Binding Path=NumberCorrect,Mode=OneWay}"></TextBlock>
  41.             </StackPanel>
  42.             <ListView x:Name="MainListView"  ItemTemplate="{StaticResource RowTemplate}">
  43.                    
  44.             </ListView>
  45.         </StackPanel>
  46.  
  47.     </Grid>
  48. </Window>

Some codebehind, no magic:

Code Snippet
  1. public partial class Window1 : Window
  2. {
  3.   private EcoProjectMathPractice.EcoProjectMathPracticeEcoSpace ecoSpace;
  4.   private Eco.WinForm.EcoAutoFormExtender ecoAutoForms;
  5.   public Window1()
  6.   {
  7.     ecoSpace = new EcoProjectMathPractice.EcoProjectMathPracticeEcoSpace();
  8.     ecoSpace.Active = true;
  9.     Eco.WPF.WPFDequeuer.Active = true;
  10.     ViewDefinitionsInApplication.Init(ecoSpace);
  11.     InitializeComponent();
  12.     ecoAutoForms = new Eco.WinForm.EcoAutoFormExtender(); // optional
  13.   }
  14.  
  15.  
  16.   private void Button_Click(object sender, RoutedEventArgs e)
  17.   {
  18.     Session session = new Session(ecoSpace);
  19.     session.CreateSessionType1();
  20.     MainListView.DataContext = session;
  21.     MainListView.ItemsSource = session.Calculation;
  22.     Main.DataContext = session;
  23.   }
  24.  
  25.   private void Button_Click_1(object sender, RoutedEventArgs e)
  26.   {
  27.     Session session = new Session(ecoSpace);
  28.     session.CreateSessionType2();
  29.     MainListView.DataContext = session;
  30.     MainListView.ItemsSource = session.Calculation;
  31.     Main.DataContext = session;
  32.   }
  33.  
  34.   private void Button_Click_2(object sender, RoutedEventArgs e)
  35.   {
  36.     Session session = new Session(ecoSpace);
  37.     session.CreateSessionType3();
  38.     MainListView.DataContext = session;
  39.     MainListView.ItemsSource = session.Calculation;
  40.     Main.DataContext = session;
  41.   }
  42. }
  43.  
  44. [ValueConversion(typeof(string), typeof(Brush))]
  45. public class MyConverter : IValueConverter
  46. {
  47.   public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  48.   {
  49.     string backColor = (string)value;
  50.     if (backColor == "red")
  51.       return new LinearGradientBrush(Colors.Red, Colors.PaleVioletRed, new Point(0, 0), new Point(1, 1));
  52.     if (backColor == "green")
  53.       return new LinearGradientBrush(Colors.Green, Colors.GreenYellow, new Point(0, 0), new Point(1, 1));
  54.     return new LinearGradientBrush(Colors.Gray, Colors.LightGray, new Point(0, 0), new Point(1, 1));
  55.   }
  56.  
  57.   public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  58.   {
  59.     return DependencyProperty.UnsetValue;
  60.   }
  61. }

The result looks like this:

image

Conclusion

Using an OCL-Derived attribute like “Correct” is a declarative way to explain what the expected result should be. Then letting other OCL-derived attributes use “Correct” like “Session.NumberOfCorrect = self.Calculation->select(a|a.Correct)->size” is fascinating way to take software development to the next level. No more need you catch the exit event of  TextBox containing the Answer – the rules are already in place – and the derived attributes automatically subscribe to the change of the attributes and associations they use. Taking this descriptive approach to information design and combining it with a descriptive way to design UI like WPF or Silverlight really is different than what the rest of the development world is doing. Is it the future? Who knows – I am hooked anyway – I will NEVER leave this line of thought or these tools. 

Side note; Simon asked me if this was the stuff I did at work all day long. I sort of reluctantly said “Yes” – afraid he would think I was a total looser. But he said “Cool job!”. Puh!

Going home in two days – Simon is better at math and we are all Tanned.

This entry was posted in ViewModel, WPF. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*