Monday, June 23, 2014

Creating real world WPF applications with Prism 5 and F# (part 2 - MEF)

In the previous post I explained how you could port the Hello World example from the Quick Starts of Prism 5. There was one issue. The Shell had knowledge op the module. This could be solved in different ways, for instance with configuration files.

I prefer a pluggable solution. Just by dropping dlls into a directory and everything should work fine. Microsoft has a framework that supports this way of working: Managed Extensibility Framework (MEF).

In this post I will show you how you can move the Hello World example from Unity to MEF.

I start from scratch and highlight the MEF changes You could also rework the Unity solution.

Create a empty solution, and add a project called Shell.

Next add:

  • FsXaml in case you don’t want to use the Xaml Type provider
  • Prism
  • the Prism.MEFExtensions.

image

If needed add the required references

image

In this case we added also System.ComponentModel.Components to get access to MEF.

image

Make sure it is a Windows application:

image

Next remove, add or rename the files

image

and be sure the xaml file has Resource as build action and contains the following content.

<Window 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.codeplex.com/prism"
Title="Hello World" Height="300" Width="300">
<
ItemsControl Name="MainRegion" cal:RegionManager.RegionName="MainRegion" />
</
Window>

We have done all the preparation. So we add the app class and the boodstrapper to the App.fs file.

module MainApp

open System
open System.IO
open System.Windows
open System.ComponentModel.Composition
open System.ComponentModel.Composition.Hosting
open System.Windows.Controls
open Microsoft.Practices.Prism.Modularity
open Microsoft.Practices.Prism.MefExtensions
open FsXaml

type Shell = XAML<"Shell.xaml">

type App() =
inherit Application()
override x.OnStartup(e) =
base.OnStartup(e)
let bootstrapper = new Bootstrapper()
bootstrapper.Run()

and Bootstrapper() =
inherit MefBootstrapper()
override x.CreateShell() =
let window = Shell()
window.CreateRoot() :> DependencyObject
override x.InitializeShell() =
base.InitializeShell()
App.Current.MainWindow <- x.Shell :?> Window
App.Current.MainWindow.Show()
override x.ConfigureAggregateCatalog() =
let path = @"..\..\..\DirectoryModules"
let dir = new DirectoryInfo(path);
if not dir.Exists then dir.Create()
let catalog = new DirectoryCatalog(path)
x.AggregateCatalog.Catalogs.Add(catalog)

[<STAThread>]
(
new App()).Run()|> ignore

Let’s compare this with Unity file from the previous post. First I have added or renamed some namespaces.


The app class did not change.


The bootstrapper now derives from MefBootstrapper. In this case we override the ConfigureAggregegateCatalog. We add a DirectoryModules directory in case it did not exists. This will prevent the creation of an exception by the DirectoryCatalog in case the directory id not exist. Next we add the catalog to the AggegateCatalog. Mef and Prism are now able to handle dll’s that are put into DirectoryModules directory.


F5 and everything works fine


image


and we have created the directory.


image


Next we create the Hello World Module again by taking the same steps as we did with the Shell. Except this time we create a dll.


image


The xaml of the HelloWorldView is the same as in the Unity example:

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<
Grid>
<
TextBlock Text="Hello World" Foreground="Green" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Calibri" FontSize="24" FontWeight="Bold"></TextBlock>
</
Grid>
</
UserControl>

Next step is to create the module:

namespace HelloWorldModule

open System
open System.Windows
open System.Windows.Controls
open System.ComponentModel.Composition

open Microsoft.Practices.Prism.Modularity
open Microsoft.Practices.Prism.Regions
open Microsoft.Practices.Prism.Mvvm
open Microsoft.Practices.Prism.MefExtensions.Modularity

open FsXaml

type HelloWorldXaml = XAML<"HelloWorldView.xaml">

[<ModuleExport(typeof<HelloWorldModule>)>]
type HelloWorldModule =
val regionViewRegistry: IRegionViewRegistry
interface IModule with
member
x.Initialize() = x.regionViewRegistry.RegisterViewWithRegion("MainRegion", fun _ -> HelloWorldXaml():> obj)
[<ImportingConstructor>]
new (regionViewRegistry) = {regionViewRegistry = regionViewRegistry}

Some of the namespaces were renamed or added.


This time we need to handle the MEF requirements. We need to add attributes. The class has the ModuleExport attribute. This attribute is provided by Prism:


image


and take care of the registration of the module.


This time we can’t use the default constructor because we need to add the ImportingConstructor attribute to the constructor.


There is no way in F# to add an attribute to the primary constructor.


image


So we need to transfer the constructor and add the attribute to this constructor with the keyword new and use an explicit field regionViewRegistry with the val keyword. In this way MEF is able handle the construction of the class by providing a value for regionViewRegistry.


image


Now we are ready to test the program. If we run it we don’t get the green Hello World. We need to copy


image


to the DirectoryModules.


image


The dll was dynamically loaded and added to the Shell.


If you don’t like to copy the dll by hand every time you change it, you could add  a post-build event


copy /y "$(TargetPath)" "..\..\..\DirectoryModules"


image


and forcing to build the module.


image


When we change the color of Hello World to red, recompilation will show us the result in the correct color.


image


Next time we will have a look at MVVM by adding functionality to the view and the new Prism 5 ViewModelLocationProvider.

Monday, June 16, 2014

Creating real world WPF applications with F# and Prism 5 (part 1)

 

F#

The designer tools of the Visual Studio should support F#. This would be critical for the adoption of F#. This is what I thought.

Last year I joined a large and complex project. The created system consists of several loosely coupled C# applications. Some components, the clients, have a WPF user interface. Some of the requirements are: easy to configure, extensibility and customization of the clients. It was decided to use modern design patterns like MVVM. It was also decided to create a composite clients. We could have created our own framework, but we decided to use one of the available frameworks: Prism 4.2 of Microsoft.

I learned that Visual Studio UI-designers are not essential for most of the development work. Blend is used by our UI-designers and the number of lines of code in the code behind code files is nearly zero. When implementing modern patterns like MV* (MVVM, MVC, MVP, etc. ), the tools should be great at designing UI’s and should have minimal integration with the code behind.

This leads to the conclusion that designer support of F# in not essential.

Prism 5

This year Prism 5 is released. As an experiment I want to build a real world application that consists of: Prism 5, XAML and F# an no C# code.

This application consists of 5 projects:

  • The shell, this is the container of the application.
  • Infrastructure, this is used to contain shared functionality between projects. It contains:
    • Base classes
    • Interfaces
    • Internal services
  • and 3 modules:
    • The Hello World module says hello to the world
    • The Prime module to determine the primeness of input
    • The message display module to show the results of the other modules

Components in Prism are called modules and these modules are not related to F# modules.

The final result looks like this:

image

Of course this is not really a real world application. It does not contain any really useful functionality and in a real world situations you could choose other ways to solve issues. I just kept it simple. I want to show how you could use Prism 5, its features together with F#.

Prism is a framework created by Microsoft patterns & practices. Prism is composite application framework. One of advantages of using a composite application is the reduction of complexity by separating concerns into functional components. Complexity increases linear with the number of components instead of quadratic and problems can simply be isolated. The details of Prism can be found at: Developer's Guide to Microsoft Prism Library 5.0 for WPF.

Prism 5 was released in April 2014. It replaces version 4.2. In the new release:

  • The dependency on Silverlight were removed.
  • Prism was modularized
  • Contains portable projects
  • Some components were replaced (the event aggregator) or a new (the ViewModelLocationProvider)

All the details of the changes can be found at: What's New in Prism Library 5.0 for WPF.

 

Hello World

In this first post I will port the Hello World from the Quickstarts of Prism to F#.

17: Getting Started Using the Prism Library 5.0 for WPF Hands-on Lab.

image

I will explain some details of the operation of Prism. Prism does contain a very detailed documentation, the missing details can be found over there. I will also discuss some F# language features. Prism is a framework created in c#, so we have to look at .NET classes, interfaces and inheritance.

Starting point of our port is the F# empty windows app (WPF) template. This template is created by Daniel Mohl:

F# Empty Windows App (WPF)

image

This template will enable us to use the XAML Type provider and it provides us the required assembly references.

After installing the VS template we use it to create a solution and a new project.

image

This project will contain the shell. The shell is the main component in a Prism solution. The shell does what it promises to do: it is a container and like most containers it is a simple box. It should have no knowledge of the content so the aim is to keep the shell as agnostic of its content as possible.

The Prism shell consists of three parts:

  • The view, this is UI part of the shell and is defined is XAML.
  • The app, this is the WPF functionality to manage the life time of the application.
  • The bootstrapper, this is the prism functionality to create the infrastructure so the modules can live.

clip_image002[5]

Then we install the required Prism libraries from nugget:

clip_image004

Prism requires the use of dependency injection framework. It does not implements its own framework, provides two integrations:

Both are provided by Microsoft.

It is possible to build an integration with your own favorite dependency injection framework.

The Hello World Quickstart uses Unity.

Next we remove the ApplicationResources.xaml file and rename the MainWindow.xaml file to Shell.xaml.

The Shell.xaml is a simple:

<Window 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.codeplex.com/prism"
Title="Hello World" Height="300" Width="300">
<
ItemsControl Name="MainRegion" cal:RegionManager.RegionName="MainRegion" />
</
Window>

The XAML contains two Prism element:


  • The prism name space
  • A placeholder so modules can present their content and functionality.

Next we delete all content of the app file.


First we add the module name and the name spaces:

module MainApp

open System
open System.Windows
open System.Windows.Controls
open Microsoft.Practices.Prism.Modularity
open Microsoft.Practices.Prism.UnityExtensions
open FSharpx

Next we make the Shell view available as a type:

type Shell = XAML<"Shell.xaml">

Now we need to create two classes that reference each other. In F# we have to define these classes at the same time by adding and:

App inherits from the Application class, the WPF class manages the lifetime of the application and provide the WPF functionality.

In the derived class we override the OnStartUp method and create a new instance of the Bootstrapper and call the Run method.

The bootstrapper derives from the UnityBootstrapper which derives from the abstract Bootstrapper both part of Prism. The abstract Bootstrappper provides the generic functionality from Prism, the UnityBootstrapper implements the Unity specific functionality.

The bootstrapper has serveral methods that can be overwritten to adjust the bootstrapper. We start with overwriting CreateShell method and InitializeShell;

type App() =
inherit Application()
override x.OnStartup(e) =
base.OnStartup(e)
let bootstrapper = new DemoBootstrapper()
bootstrapper.Run()

and DemoBootstrapper() =
inherit UnityBootstrapper()
override x.CreateShell() =
let window = Shell()
window.Root :> DependencyObject
override x.InitializeShell() =
base.InitializeShell()
App.Current.MainWindow <- x.Shell :?> Window
App.Current.MainWindow.Show()
override x.ConfigureModuleCatalog() =
base.ConfigureModuleCatalog()
let moduleCatalog = x.ModuleCatalog :?> ModuleCatalog
moduleCatalog.AddModule(typeof<HelloWorldModule.HelloWorldModule>) |> ignore

We end with the start method:

[<STAThread>]
(
new App()).Run()|> ignore

When we compile and run the application an empty shell is presented.

image

Next task: create a module that can be shown in the shell.

Create a new project of type F# Empty Windows App (WPF) and change the project output type to class library. One could start with a library project, in that case all required references have to be added by hand. Call the project HelloWorldModule.

Again we remove the ApplicationResources.xaml file and rename the MainWindow.xaml file. In this case to HelloWorldView.xaml.

Next we add references to the Prism dlls.

image

Again the XAML is very simple:

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<
Grid>
<
TextBlock Text="Hello World" Foreground="Green" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Calibri" FontSize="24" FontWeight="Bold"></TextBlock>
</
Grid>
</
UserControl>

It will show the green text: “Hello World”.

Again we remove all code from the App file. We add the name space and open the required namespaces

namespace HelloWorldModule

open System
open System.Windows
open System.Windows.Controls

open Microsoft.Practices.Prism.Modularity
open Microsoft.Practices.Prism.Regions
open Microsoft.Practices.Prism.Mvvm

open FSharpx

Next we add the XAML of the view as a type.

type HelloWorldXaml = XAML<"HelloWorldView.xaml">

Now we create the main object of the module: the HelloWordModuel. This is a class that implements the IModule interface of Prism. The interface has one method, Initialize. This method does all the work to make the module available.

In our case we need register the view and add it to the “MainRegion”. This is the region we defined in the shell. To be able to register the view, the module needs access the RegionViewRegistry. It gets this by receiving a reference from the constructor.

type HelloWorldModule(registry:IRegionViewRegistry) =
let mutable regionViewRegistry = registry
interface IModule with
member
x.Initialize() = regionViewRegistry.RegisterViewWithRegion("MainRegion", fun _ -> HelloWorldXaml().Root:> obj)

The module is ready for use. The last activity is to tell the shell the module exits. This can be done is several ways. The Hello World implementation takes to easy way by adapting the bootstrapper. We add an extra override to the boostrapper. This time we override ConfigureModuleCatalog by adding our HelloWorldModule. The module catalog contains all available modules.

type App() =
inherit Application()
override x.OnStartup(e) =
base.OnStartup(e)
let bootstrapper = new DemoBootstrapper()
bootstrapper.Run()

and DemoBootstrapper() =
inherit UnityBootstrapper()
override x.CreateShell() =
let window = Shell()
window.Root :> DependencyObject
override x.InitializeShell() =
base.InitializeShell()
App.Current.MainWindow <- x.Shell :?> Window
App.Current.MainWindow.Show()
override x.ConfigureModuleCatalog() =
base
.ConfigureModuleCatalog()
let
moduleCatalog = x.ModuleCatalog :?> ModuleCatalog
moduleCatalog.AddModule(typeof<HelloWorldModule.HelloWorldModule>) |>
ignore

When we compile and run the application the Hello World Module is present, the green Hello World Text is shown.


clip_image002[7]


This completes the port of the Hello World from the Quickstarts of Prism 5 to F#.

There is at least one problem with the Hello World implementation. The Shell has to have knowledge of the HelloWorldModule.

Next time we have a look how we can fix this. There are other ways to configure Module Catalog. If we use Managed Extensibility Framework (MEF) as the dependency injection framework we can even can reduce the configuration to copying module dlls into directory.


Updates:



  • I got a tweet from Reed Copsey (@ReedCopsey). He suggested to use FsXaml. By getting a version via Nuget:
  • image

replace the namespaces:


    open FsXaml

and adjusting the creation of the view:

and DemoBootstrapper() =
inherit UnityBootstrapper()
override x.CreateShell() =
Shell().CreateRoot() :> DependencyObject
override x.InitializeShell() =
base.InitializeShell()
App.Current.MainWindow <- x.Shell :?> Window
App.Current.MainWindow.Show()
override x.ConfigureModuleCatalog() =
base.ConfigureModuleCatalog()
let moduleCatalog = x.ModuleCatalog :?> ModuleCatalog
moduleCatalog.AddModule(typeof<HelloWorldModule.HelloWorldModule>) |> ignore

it works again.


Monday, June 17, 2013

Increase your productivity with F# scripts (part 2)

Last post we discussed a real world problem, cleanup your test environment after a complex integration test. We used a F# script to do the work.

This time we look add more advanced scenario’s and solutions. First we want to split our script file into two files. One containing the scenario related code and one containing a library of facade function we want to reuse.

We start by creating a new script file in the Scripts directory calling it Lib.fsx and open the file with a text editor. Next we open also the script file we created last time and add the following lines of code:

#load "Lib.fsx"
open Lib 

The first line links the script file to the newly created Lib file. The second line opens the namespace “Lib”, the default namespace of the functions in the Lib script file.

Next we move the facade functions (including the reference to the namespaces) to the Lib file.

SplitSource

After this refactoring everything still works the way it used to work.

Next want to create a startup script. Every time we start the laptop we want start with a clean log directory, we like a clean machine and second we want open a Visual Studio Solution so we can start coding immediately.

We start by creating a new script file called Startup.fsx and the following code:

#load "Lib.fsx"
open Lib

["E:\\Log"] |> List.iter(deleteContentOfDirectory)

Again we connect to Lib file and reuse the deleteContentOfDirectory function we created last time to clean the Log directory.

Next we create a new shortcut like we did the last time:

StartUp_Shortcut

This time linking it to the Startup script.

After testing the script we move the shortcut to the following directory:

C:\Users\YourAccountName\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

  StartUp_3

After we restart our machine, the Log directory is cleaned.

There are other ways to associate scripts with the startup. You can use the group policy if your version of Windows has access to it (gpedit.msc):

LocalGroupPolicy_1

Next step is to open the Visual studio solution.

We add the following facade function to Lib.fsx

let startProcess fileName =
    let newProcess = new Process()
    newProcess.StartInfo.FileName <- fileName
    newProcess.Start() |> ignore

and the following line to the StartUp script

startProcess @"E:\VS\Test\Test.sln"

VS

the next time you start up the log directory is clean and your Solution will be directly available.

Adding extra functionality to the scripts is now a trivial activity.

My Lib files contains, for example, exception handling and some reporting:

ExceptionHandling

This will not stop the script in case a file can not be deleted. The exception will be reported to the console.

There are a lot of activities that can be automated, I have scripts that:

  • Start programs like a mail client.
  • Creating zipped backups of source code.

In this way I can improve my productivity with F# scripting. How can F# scripting increase your productivity?

Thursday, June 13, 2013

Increase your productivity with F# scripts (part 1)

 

One of the many nice features of F# is its scripting capability. There are other scripting languages like PowerShell to improve your productivity on a Windows system. In this case you need to learn a new language and a new environment to automate some basic tasks. When you know F# and .NET you can leverage your skills, so let’s look at F# scripting.

 

A simple real-world problem

I once was responsible for integration testing a complex set of applications. After completing the test several applications were still running so these processes had to be stopped with the Task Manager and several directories had to be cleaned. How could F# help me to be more productive?

Let’s start by creating a directory called Scripts, add a new text file and rename it to EndIntegrationTest.fsx.

Create_EnIntegrationTest

open the file with your favorite text editor, I use Notepad++ in this case and 

add the line:

System.Diagnostics.Process.GetProcessesByName("app1") |> Seq.iter(fun x -> x.Kill())

This will “kill” all programs that are called app1 by first looking for all processes called app1 and next kill them one by one.

Create_EnIntegrationTest_1

I have set the Language menu to Caml to get some syntax highlighting.

Next we change the program associated with the file extension, right click:

ChangeProgramme

Look for another app on this PC (this is Windows 8) and look for the following directory:

C:\Program Files (x86)\Microsoft SDKs\F#\3.0\Framework\v4.0

Fsi

and select fsi.exe.

To test the script I created a C# console app and called it app1, start the executable in the debug directory

Before

Open the script file and app1 will be killed (R.I.P. app1).

After

This scripting solution has some drawbacks which we will discuss later, but it works. It matches the first rule of scripting:

Keep your scripts as simple as possible.

Scripts should increase your productivity and you should not spend much time on debugging or creating functionality you do not need (YAGNI –> You aren't gonna need it).

In case I want to kill app1 I have to go to the scripting directory. I can become more productive if I add a shortcut to my desk

CreateShortcut

rename it “Shortcut_EndIntegrationTest” and move it to the desktop.

Shortcut

The next step is to change some of the properties of the shortcut, Shortcut key and Run, 

ShortcutProperties

After these changes all I have to do is press CRTL + ALT + 1 after the test is completed and the script runs without showing a console.

One of the drawbacks of the the created solution is that we have associated the .fsx extension with the fsi.exe. In this way we can run an F# script by accident when we just want to edit a file. With great power, comes great responsibility. We can fix this when associate the .fsx files with a text editor program and repair the shortcut. Also from a security perspective this is a better solution.

Go to General tab and associate .fsx with an editor

Notepadd

After apply the shortcut and all .fsx file will start the text editor.

Next change he target line to:

"C:\Program Files (x86)\Microsoft SDKs\F#\3.0\Framework\v4.0\Fsi.exe" "E:\Blog\Scripts\EndIntegrationTest.fsx”

ShortcutProperties

and the shortcut will kill app1 again (you need to repair the shortcut key and the run mode).

This script does not solve all our problems, we have to be able to kill multiple applications and we have to clean all polluted directories.

We could copy the line that killed the application and change the name of the app, but there is a second scripting rule:

Do not repeat yourself (DRY).

So we create a facade function killProcesses:

open System.Diagnostics

let killProcesses processNames =
    Process.GetProcesses()
    |> Seq.filter(
fun p ->
       
processNames|> List.exists (fun name -> name = p.ProcessName))
    |> Seq.iter(
fun x -> x.Kill())
   

and call it with a list of application name:

killProcesses ["app1"; "app2"]

this replaces the initial code.

killAll

CTRL + ALT + 1

and all are processes are killed.

Next we add the facade function to clean the directories:

let deleteContentOfDirectory path =
Directory.EnumerateDirectories(path) |> Seq.iter(
fun dir -> Directory.Delete(dir, true))
Directory.EnumerateFiles(path) |> Seq.iter(File.Delete)

We enumerate through all content in the directory, sub directories and files and delete them all. We use the facade function to clean all required directories:


["E:\\CleanUpTest1"; "E:\\CleanUpTest2"] |> List.iter(deleteContentOfDirectory)


Before:

CleanDirBefore 
After:
CleanDirAfter 

So we have solved our real-world problem.


Next time we improve our solution by putting the facade functions in a library and we look at startup scripts.


Update:At a windows machine not containing F# Script (REPL), you can add it yourself. Here are all the details: A step by step guide to installing an F# REPL environment on Windows by Matthew Adams.

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:

PrimeSequence

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:

PrimeSequenceWinRT1

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):

PrimeSequenceWinRT2

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
let addElements(collection:ObservableCollection<MathLib.Element>) =
    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)
{
    ViewModel.addElements(this.Collection);
}

F5 and the application never shows the Main Page:

screenshot_01292013_114516

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.

screenshot_01292013_114929

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)
{
    await ViewModel.addElementsTask(this.Collection);
}

and change the ViewModel
module ViewModel
open System.Collections.ObjectModelopen System.Threading.Tasks
let addElements(collection:ObservableCollection<MathLib.Element>) =
    MathLib.primeSequence|> Seq.iter collection.Add

let addElementsTask(collection:ObservableCollection<MathLib.Element>) =
     collection.Clear()

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

This time we get error messages:

Error

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
open System.Collections.ObjectModelopen System.Threading.Tasks
let addElements(collection:ObservableCollection<MathLib.Element>) = 
    MathLib.primeSequence |> Seq.iter collection.Add

let addElementsTask(collection:ObservableCollection<MathLib.Element>) =
     collection.Clear()
     Task<int>.Factory.StartNew(fun _ ->
                                addElements(collection)
                                0)


F5 again. This time we get an context exception.

ContextException

So we add the context to the functions.
 protected async override void OnNavigatedTo(NavigationEventArgs e)
        {
            await ViewModel.addElementsTask(this.Collection, System.Threading.SynchronizationContext.Current);
        }

and

module ViewModel
open System.Collections.ObjectModelopen System.Threadingopen System.Threading.Tasks
let addElements(collection:ObservableCollection<MathLib.Element>, context:SynchronizationContext) =
     MathLib.primeSequence |> Seq.iter(
fun x -> context.Post((fun _ -> collection.Add(x)) ,null))
let addElementsTask(collection:ObservableCollection<MathLib.Element>, context:SynchronizationContext) =
     collection.Clear()
     Task<int>.Factory.StartNew(
fun _ ->
                               
addElements(collection,context)
                                0)



and we get the desired result:

screenshot_01292013_124616

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>.

  2. We can replace addElementsTask by
let addElementsTaskMutable (collection:ObservableCollection<MathLib.Element>, synchronizationContext:SynchronizationContext) =
    collection.Clear()
    Task<int>.Factory.StartNew(
        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.





Total Pageviews