Monday, June 28, 2010

WPF MVVM Multi-Project Template: A Polyglot Approach

In my last post, I provided a WPF MVVM multi-project template comprised entirely of F# projects.  While that approach is exciting, I found that having the Views in an F# project caused more pain than gain.  As an advocate for using the right tool for the job, I have created a new WPF MVVM multi-project template composed of an C# View project, an F# ViewModel project, and an F# Model project.  Additionally, this version includes an F# Repository project and an F# project called FSharpIoC that provides inversion of control functionality (this can easily be replaced with the IoC contrainer of your choice).

The F# code did not change significantly between this version and the last; however, the ExpenseItHomeViewModel.fs has been cleaned up due to refactoring and the introduction of the ExpenseReportRepository.

Here's the code:
namespace FSharpWpfMvvmTemplate.ViewModel

open System
open System.Windows
open System.Windows.Data
open System.Windows.Input
open System.ComponentModel
open System.Collections.ObjectModel
open FSharpWpfMvvmTemplate.Model
open FSharpWpfMvvmTemplate.Repository

type ExpenseItHomeViewModel(expenseReportRepository : ExpenseReportRepository)  =  
    inherit ViewModelBase()
    let mutable selectedExpenseReport = 
        {Name=""; Department=""; ExpenseLineItems = []}
    new () = ExpenseItHomeViewModel(
                  FSharpIoC.IoC.GetIoC.Resolve<ExpenseReportRepository>())
    member x.ExpenseReports = 
        new ObservableCollection<ExpenseReport>(
            expenseReportRepository.GetAllExpenseReports())
    member x.ApproveExpenseReportCommand = 
        new RelayCommand ((fun canExecute -> true), (fun action -> x.ApproveExpenseReport)) 
    member x.SelectedExpenseReport 
        with get () = selectedExpenseReport
        and set value = 
            selectedExpenseReport <- value
            x.OnPropertyChanged "SelectedExpenseReport"
    member x.ApproveExpenseReport = 
        MessageBox.Show(sprintf "Expense report approved for %s" x.SelectedExpenseReport.Name) |> ignore

You can find the template installer here and the full source at http://github.com/dmohl/PolyglotWpfMvvmTemplate.

Monday, June 21, 2010

An F# WPF MVVM Project Template

I've been planning for a while to create an F# WPF MVVM Template to add to the other templates that have been announced on this blog.  A resent post by Mark Pearl provided a great simple example which helped kick me into gear and bring this plan to fruition.

To get us up to date, here are the links to the other templates that I have created:

- Standard WCF Template
- Standard ASP.NET MVC 2 Template

This particular template is slightly different than the others.  While the others had most or all of the code written in F#, the views or endpoints were still provided via a C# project.  In contrast, this F# WPF MVVM template contains only F# projects.

What to Expect:

The code provided by this template creates an application that is loosely based on ExpenseIt (A simple expense report app. defined on this MSDN page). The following screenshot displays the produced application in action:


The Model:

The model for this application is comprised of two simple records:
type Expense =
    { ExpenseType : string
      ExpenseAmount : string}

type ExpenseReport =
    { Name : string
      Department : string
      ExpenseLineItems : seq<expense>}
The View Models:

The view models are fairly standard. Each view model inherits from a ViewModelBase class. The ExpenseItHomeViewModel class contains most of the code. Since these are the two most interesting classes associated with view models, they will be the only two shown.

ViewModelBase.fs
namespace FSharpWpfMvvmTemplate.ViewModel

open System
open System.Windows
open System.Windows.Input
open System.ComponentModel

type ViewModelBase() =
    let propertyChangedEvent = new DelegateEvent<PropertyChangedEventHandler>()
    interface INotifyPropertyChanged with
        [<CLIEvent>]
        member x.PropertyChanged = propertyChangedEvent.Publish
    member x.OnPropertyChanged propertyName = 
        propertyChangedEvent.Trigger([| x; new PropertyChangedEventArgs(propertyName) |])
ExpenseItHomeViewModel.fs
namespace FSharpWpfMvvmTemplate.ViewModel

open System
open System.Xml
open System.Windows
open System.Windows.Data
open System.Windows.Input
open System.ComponentModel
open System.Collections.ObjectModel
open FSharpWpfMvvmTemplate.Model

type ExpenseItHomeViewModel =   
    [<DefaultValue(false)>] val mutable _collectionView : ICollectionView
    [<DefaultValue(false)>] val mutable _expenseReports : ObservableCollection<ExpenseReport>
    new () as x = {_expenseReports = new ObservableCollection<ExpenseReport>(); 
                   _collectionView = null} then x.Initialize()
    inherit ViewModelBase
    member x.Initialize() =
        x._expenseReports <- x.BuildExpenseReports()
        x._collectionView <- CollectionViewSource.GetDefaultView(x._expenseReports)
        x._collectionView.CurrentChanged.AddHandler(
            new EventHandler(fun s e -> x.OnPropertyChanged "SelectedExpenseReport")) 
    member x.BuildExpenseReports() = 
        let collection = new ObservableCollection<ExpenseReport>()
        let mike = {Name="Mike" 
                    Department="Legal" 
                    ExpenseLineItems = 
                        [{ExpenseType="Lunch" 
                          ExpenseAmount="50"};
                        {ExpenseType="Transportation" 
                         ExpenseAmount="50"}]}
        collection.Add(mike)
        let lisa = {Name="Lisa"
                    Department="Marketing" 
                    ExpenseLineItems = 
                        [{ExpenseType="Document printing" 
                          ExpenseAmount="50"};
                        {ExpenseType="Gift" 
                         ExpenseAmount="125"}]}
        collection.Add(lisa)
        let john = {Name="John" 
                    Department="Engineering"
                    ExpenseLineItems = 
                        [{ExpenseType="Magazine subscription" 
                          ExpenseAmount="50"};
                        {ExpenseType="New machine" 
                         ExpenseAmount="600"};
                        {ExpenseType="Software" 
                         ExpenseAmount="500"}]}
        collection.Add(john)
        let mary = {Name="Mary"
                    Department="Finance"
                    ExpenseLineItems = 
                        [{ExpenseType="Dinner" 
                          ExpenseAmount="100"}]}
        collection.Add(mary)
        collection
    member x.ExpenseReports : ObservableCollection<ExpenseReport> = x._expenseReports
    member x.ApproveExpenseReportCommand = 
        new RelayCommand ((fun canExecute -> true), (fun action -> x.ApproveExpenseReport)) 
    member x.SelectedExpenseReport =
        x._collectionView.CurrentItem :?> ExpenseReport
    member x.ApproveExpenseReport = 
        MessageBox.Show(sprintf "Expense report approved for %s" x.SelectedExpenseReport.Name) |> ignore
The Views:

The views are similar to views used in any WPF MVVM application. The solution has three XAML files: ApplicationResources.xaml, MainWindow.xaml, and ExpenseItHome.xaml. Since ExpenseItHome.xaml is the most interesting of these three, it is provided below:
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" 
      xmlns:ViewModel="clr-namespace:FSharpWpfMvvmTemplate.ViewModel;assembly=FSharpWpfMvvmTemplate.ViewModel" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignWidth="424">
    <UserControl.DataContext>
        <ViewModel:ExpenseItHomeViewModel></ViewModel:ExpenseItHomeViewModel>
    </UserControl.DataContext>
    <UserControl.Resources>
        <ResourceDictionary Source="ApplicationResources.xaml" />
    </UserControl.Resources>
    <Grid Margin="10,0,10,10" VerticalAlignment="Stretch">

        <Grid.Resources>
            <!-- Name item template -->
            <DataTemplate x:Key="nameItemTemplate">
                <Label Content="{Binding Path=Name}"/>
            </DataTemplate>
            <!-- Expense Type template -->
            <DataTemplate x:Key="typeItemTemplate">
                <Label Content="{Binding Path=ExpenseType}"/>
            </DataTemplate>
            <!-- Amount item template -->
            <DataTemplate x:Key="amountItemTemplate">
                <Label Content="{Binding Path=ExpenseAmount}"/>
            </DataTemplate>

        </Grid.Resources>

        <Grid.Background>
            <ImageBrush ImageSource="watermark.png"  />
        </Grid.Background>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <!-- People list -->
        <Label Grid.Row="0" Grid.ColumnSpan="2" Style="{StaticResource headerTextStyle}" >
            View Expense Report
        </Label>
        <Grid Margin="10" Grid.Column="0" Grid.Row="1" VerticalAlignment="Top">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>

            <Border Grid.Row="1" Style="{StaticResource listHeaderStyle}">
                <Label Style="{StaticResource listHeaderTextStyle}">Names</Label>
            </Border>

            <ListBox Name="peopleListBox" Grid.Row="2" 
                 ItemsSource="{Binding Path=ExpenseReports}"
                 ItemTemplate="{StaticResource nameItemTemplate}"
                 IsSynchronizedWithCurrentItem="True">
            </ListBox>

            <!-- View report button -->
        </Grid>
        <Grid Margin="10" Grid.Column="1" Grid.Row="1" DataContext="{Binding SelectedExpenseReport}" VerticalAlignment="Top">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="57*" />
                <ColumnDefinition Width="125*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <!-- Name -->
            <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Orientation="Horizontal">
                <Label Style="{StaticResource labelStyle}">Name:</Label>
                <Label Style="{StaticResource labelStyle}" Content="{Binding Path=Name}"></Label>
            </StackPanel>
            <!-- Department -->
            <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Orientation="Horizontal">
                <Label Style="{StaticResource labelStyle}">Department:</Label>
                <Label Style="{StaticResource labelStyle}" Content="{Binding Path=Department}"></Label>
            </StackPanel>
            <Grid Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2" VerticalAlignment="Top" HorizontalAlignment="Left">
                <!-- Expense type and Amount table -->
                <DataGrid ItemsSource="{Binding Path=ExpenseLineItems}" ColumnHeaderStyle="{StaticResource columnHeaderStyle}" AutoGenerateColumns="False" RowHeaderWidth="0" Margin="0,0,-139,0">
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="ExpenseType" Binding="{Binding Path=ExpenseType}"  />
                        <DataGridTextColumn Header="Amount" Binding="{Binding Path=ExpenseAmount}" />
                    </DataGrid.Columns>
                </DataGrid>
            </Grid>
        </Grid>
        <Button Grid.Row="2" Command="{Binding ApproveExpenseReportCommand}" Style="{StaticResource buttonStyle}" Grid.Column="1" Margin="0,10,53,0">Approve</Button>
    </Grid>
</UserControl>
Conclusion:

You can download the template installer here and find the full source at http://github.com/dmohl/FSharpWpfMvvmTemplate.  I did run into a few limitations with having the views in an F# project.  Because of these limitations, I would likely use a polyglot approach with a C# project as the view container and F# projects for the model and view model containers for solutions that are any more complex than this example.  I plan to provide a template for the polyglot approach in my next blog post. 

Wednesday, June 16, 2010

Son of a Son of Obsidian (My Favorite VS2010 Theme)

A month or two ago I had a great time going through all of the Visual Studio themes that can be found out on http://studiostyles.info/. After trying several of them out, I landed on Son of Obsidian.  Here is an example of what this theme looks like when developing in F#:


While I really liked Son of Obsidian, there were a few settings that made my eyes hurt.  After tweaking font colors specific to Resharper, Visual Studio 2010 Productivity Power Tools, etc., I can now say that this is officially my favorite theme.

How Can I Get It?

A few people have asked how they can get this slightly modified version of Son of Obsidian.  This can be accomplished by doing the following:

1. Download Son of a Son of Obsidian here.
2. Open Visual Studio 2010.
3. Select "Tools" then "Import and Export Settings..." from the main menu.


4. In the resulting wizard, select "Import selected environment settings" and click "Next".
5. Select "No, just import new settings, overwriting my current settings" and click "Next".
6. Click the browse button, locate the file that you downloaded in step 1, and select it.  Then click "Next".
7. Click Finish.
8. Finally, assuming the import is successful, click "Close".

Sunday, June 13, 2010

The Standard WCF Service Application Template for F#

In the interest of building up a larger set of installed templates for F#, I've ported the standard C# WCF Service Application to F# and packaged it into a .vsi file.

Here are a few snippets from the solution that the template creates:

IService1.fs
namespace FSharpWcfServiceApplicationTemplate.Contracts

open System.Runtime.Serialization
open System.ServiceModel

[<ServiceContract>]
type IService1 =
    [<OperationContract>]
    abstract GetData: value:int -> string
    [<OperationContract>]
    abstract GetDataUsingDataContract: composite:CompositeType -> CompositeType
Service1.fs
namespace FSharpWcfServiceApplicationTemplate

open System
open FSharpWcfServiceApplicationTemplate.Contracts 

type Service1() =
    interface IService1 with
        member x.GetData value =
            sprintf "%A" value
        member x.GetDataUsingDataContract composite =
            match composite.BoolValue with
            | true -> composite.StringValue <- 
                          sprintf "%A%A" composite.StringValue "Suffix"
            | _ -> "do nothing" |> ignore
            composite
You can download the installer from here and get the full source from http://github.com/dmohl/FSharpWcfServiceApplicationExample.

Monday, June 7, 2010

FSharpCouch: A Simple CouchDB .NET API in F#


In one of my last posts I showed a simple web application (created with the help of WebSharper Platform 2010) that captured registration information from a user and saved it to a CouchDB database.  I've been using CouchDB for a while now and I'm still amazed at how quickly you can get things up and running when you don't have to worry about the object-relational impedance mismatch.

To interact with CouchDB, I primarily use Relax (a full featured ".NET API abstraction of CouchDB's (excellent) RESTful API"); however, I thought it might be fun and educational to create a simple CouchDB .NET API abstraction in F#.  Note: The code provided  here is loosely based on SharpCouch.

Just Show Me the Code:

Without any further ado, here's the code.
module FSharpCouch
    open System
    open System.Net
    open System.Text
    open System.IO
    open Newtonsoft.Json
    open Newtonsoft.Json.Linq

    let WriteRequest url methodName contentType content =
        let request = WebRequest.Create(string url)
        request.Method <- methodName
        request.ContentType <- contentType 
        let bytes = UTF8Encoding.UTF8.GetBytes(string content)
        use requestStream = request.GetRequestStream()
        requestStream.Write(bytes, 0, bytes.Length) 
        request
    let AsyncReadResponse (request:WebRequest) =
        async { use! response = request.AsyncGetResponse()
                use stream = response.GetResponseStream()
                use reader = new StreamReader(stream)
                let contents = reader.ReadToEnd()
                return contents }
    let ProcessRequest url methodName contentType content =
        match methodName with
        | "POST" -> 
            WriteRequest url methodName contentType content
        | _ -> 
            let req = WebRequest.Create(string url)
            req.Method <- methodName
            req
        |> AsyncReadResponse 
        |> Async.RunSynchronously
    let ToJson content =
        JsonConvert.SerializeObject content
    let FromJson<'a> json =
        JsonConvert.DeserializeObject<'a> json
    let BuildUrl (server:string) (database:string) =
        server + "/" + database.ToLower()
    let CreateDatabase server database =
        ProcessRequest (BuildUrl server database) "PUT" "" ""
    let DeleteDatabase server database =
        ProcessRequest (BuildUrl server database) "DELETE" "" ""
    let CreateDocument server database content = 
        content |> ToJson
        |> ProcessRequest (BuildUrl server database) "POST" "application/json"
    let GetDocument<'a> server database documentId =
        ProcessRequest ((BuildUrl server database) + "/" + documentId) "GET" "" ""
        |> FromJson<'a>
    let GetAllDocuments<'a> server database =
        let jsonObject = ProcessRequest ((BuildUrl server database) + "/_all_docs") "GET" "" ""
                         |> JObject.Parse
        Async.Parallel [for row in jsonObject.["rows"] -> 
                            async {return FromJson<'a>(row.ToString())}]
        |> Async.RunSynchronously
    let DeleteDocument server database documentId revision =         
        ProcessRequest ((BuildUrl server database) + "/" + documentId + "?rev=" + revision) "DELETE" "" ""
Conclusion:

F# + CouchDB = totally awesome! You can find the full solution with integration tests at http://github.com/dmohl/FSharpCouch.

Tuesday, June 1, 2010

F# Presentation for the New England F# User Group

I will be speaking at the New England F# User Group on July 5th, 2010 at 6:30 PM Eastern Time.  Here's the information:

Title: 5 Best Practices for F# Development

Abstract:

F# makes it very easy to develop high performance, readable, and efficient code. However, like all things, a lack of discipline and best practice adoption can lead to a mess. In this talk we will cover 5 best practices that you can start using today to make yourself a better F# developer. We will explore each best practice, discuss the reason(s) that the described approach is preferred, and explore a few examples.

For more information visit www.fsug.org.