## Tuesday, January 29, 2013

### Windows Store Apps with F# (part 4) : Collections

In the previous post we were introduced to data binding and MVVM. We dealt with one object. How can we deal with more than one object, a collection of objects?
This time we want to show a sequence of primes:
1. 2
2. 3
3. 5
4. 7
5. 11
The first number is the sequence number, the second is the value of the prime. We want to show this sequence in a Windows Store App. We create again a new blank Windows Store App and add a F# Portable Library. We rename the F# file to Lib.fs. Let’s follow MVVM. We start with the Model. Add the IsPrime function to Lib.fs:
```module MathLib
let IsPrime n =
if n < 2L then
false
else
seq{2L..n - 1L}
|> Seq.exists(fun x -> n % x = 0L)
|> not```

Next we create an object to represent an element in the sequence:
```type Element(sequenceNumber:int, value:int64) =
member x.SequenceNumber = sequenceNumber
member x.Value          = value```
Now it is possible to create a function that will determine the next element in the sequence of primes:  let rec nextPrime (element:Element) =

if IsPrime (element.Value + 1L) then

Element(element.SequenceNumber + 1,  element.Value + 1L)

else

Element(element.SequenceNumber,  element.Value + 1L) |> nextPrime

Next we create a sequence of all primes (details at page 320 of Real-World Functional Programming by Tomas Petricek and with Jon Skeet, buy this book!!):
```let rec primeSequence =
seq { yield Element(1,  2L)
for e in primeSequence do yield e |> nextPrime }```

and test the model by adding a test to the Script.fsx file.
```#load "Lib.fs"
MathLib.primeSequence |> Seq.take 5 |> Seq.iter( fun r -> (printfn "%d. %d" r.SequenceNumber r.Value))```

When we run the code in F# Interactive we get the expected result:

Compile the project and add a reference from the C# project to the F# project.

Next step: the Model. We contact the UI designer and he sends us the following XAML:
```<GridView ItemsSource="{Binding}" >
<GridView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>

<TextBlock Grid.Column="0"  Text="{Binding SequenceNumber}"/>
<TextBlock Grid.Column="1"  Text="->"/>
<TextBlock Grid.Column="2" Text="{Binding Value}"/>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView> ```

We past it in the Grid of the MainPage. Gridview is one of the Windows Store App controls that can display collections.

Next we update the MainPage code behind:
`using System.Collections.ObjectModel;`

and
``` public sealed partial class MainPage : Page
{
private ObservableCollection<MathLib.Element> Collection;

public MainPage()
{
this.InitializeComponent();

Collection = new ObservableCollection<MathLib.Element>()
{
new MathLib.Element(1, 2),
new MathLib.Element(2, 3),
new MathLib.Element(3, 5),
new MathLib.Element(4, 7),
new MathLib.Element(5, 11)
};

this.DataContext = Collection;
}```

We have created an ObservableCollection class called Collection and added some elements so we can see the result of the binding.

F5:

It works as expected but it does not look good.

So we contact our designer again. This is the code he sends us:
```<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="Primes" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="42" Margin="80,40,0,0" />
<GridView x:Name="ItemListView" ItemsSource="{Binding}" Margin="80, 100, 80, 80">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="200" Height="60" Background="Green">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="120"/>
</Grid.ColumnDefinitions>

<TextBlock Grid.Column="0"  Text="{Binding SequenceNumber}"  HorizontalAlignment="Left"
VerticalAlignment="Top"
FontSize="15"
Foreground="Black"
Margin="5,5,5,5" />
<TextBlock Grid.Column="2" Text="{Binding Value}"  HorizontalAlignment="Left"
VerticalAlignment="Top"
FontSize="24"
Foreground="White"
Margin="5,5,5,5"/>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Grid>```

and the result looks like this (replace the XAML and press F5):

We accept this design.

Remark: there are better ways to deal with design data in XAML: [WPF / MVVM] How to get data in “design time” ?

Now it is time to glue the Model and the View together, we will add the View Model code.

First we change the initialization of the Collection:
`  Collection = new ObservableCollection<MathLib.Element>();`

and add a new F# file to the F# project called ViewModel.

We add the following code:
```module ViewModel
open System.Collections.ObjectModel
collection.Clear()
MathLib.primeSequence |> Seq.iter collection.Add```

Build the solution and add the following code to event handler OnNavigatedTo of the MainPage:
```protected override void OnNavigatedTo(NavigationEventArgs e)
{
}```

F5 and the application never shows the Main Page:

When we reduce the number of elements to 100
```let addElements(collection:ObservableCollection<MathLib.Element>) =
collection.Clear()
MathLib.primeSequence|> Seq.take 100 |> Seq.iter collection.Add```

we get the expected result.

This solution will not work when we want to display a very large number of primes.

So we go the async/await way again.
```protected async override void OnNavigatedTo(NavigationEventArgs e)
{
}```

and change the ViewModel
```module ViewModel

collection.Clear()```

`Task.Factory.StartNew(fun _ -> addElements collection);`

This time we get error messages:

The C# project needs a reference to the F# library. We will not go that way, we solve the issue by creating a Task of int and add a dummy return value.
```module ViewModel
MathLib.primeSequence |> Seq.iter collection.Add

collection.Clear()
0)```

F5 again. This time we get an context exception.

So we add the context to the functions.
``` protected async override void OnNavigatedTo(NavigationEventArgs e)
{
}```

and

module ViewModel
let addElements(collection:ObservableCollection<MathLib.Element>, context:SynchronizationContext) =
MathLib.primeSequence |> Seq.iter(
fun x -> context.Post((fun _ -> collection.Add(x)) ,null))
collection.Clear()
fun _ ->

0)

and we get the desired result:

We end with two small remarks:

1. In this post we used the ObservableCollection, this is a .NET solution. The WinRT way is to use IObservableVector<T>.

```let addElementsTaskMutable (collection:ObservableCollection<MathLib.Element>, synchronizationContext:SynchronizationContext) =
collection.Clear()
fun _ ->
let mutable e = MathLib.Element(0,  1L)
while true do
e <- MathLib.nextPrime e
let x = e  //make the result immutable
synchronizationContext.Post((fun _ -> collection.Add(x)) ,null)
0
)```
This seems to improve the performance of the application quit a lot.

#### 1 comment:

Unknown said...

I've finished the series now and want to say thanks, again. The WinRT and F# issues you've addressed here will be a huge help to me, and I'm so glad that I worked through all of your tutorial before starting on my app.

I'm looking forward to doing this work. F# just rocks in .Net!