Quickstart WPF F#-only app in VSCode

Almost every aspect of the WPF application is customisable. It also saves hours by providing data-binding mechanism. And it is much more easy to understand code that was created following the MVVC pattern. Mainly because that this knowledge is shared and if you know this pattern then you know what to expect from the application that follows it.

F# adds value too. It is concise, functional and picky about nulls and mutability. The type providers is a great time-saver as well.

The editor is a forge. There are many, but three are significally better for Windows-specific programming. VS Studio, Rider and VS Code. The later has very small footprint and free. Although it is very powerful and provides Visual Studio level of tooling in some areas, it is still very close to the ground. It is more a text editor than IDE, which makes it a good choice for some projects.

Note: Installed VS Code with lonide-fsharp is required to continue.

Perhaps the most easy way to start is to create the solution and project file from the Visual Studio and then switch to the VS Code.

Here is the initial file structure of the project:

./WPFFSharpQuickStart/
  MyApp/
    App.config
    App.xaml
    AssemblyInfo.fs
    MainViewModel.fs
    MainWindow.xaml
    MyApp.fsproj
    Program.fs
  MyApp.Libary/
    AssemblyInfo.fs
    MyApp.Libary.fsproj
    Services.fs
  WPFFSharpQuickStart.sln

The solution consists of two projects. App, which is the first one, is the WPF application itself. It is for presentation-related code, like XAML files, view models, converters, etc. Srv is where to put the application logic like services, etc. App references Srv.

The solution and project files should be created manually. As far as I know there is no command line tooling for that. It is always possible to use Visual Studio, of course.

Instead of creating them manually, you can try to clone it from this GitHub project:

PS C:\Projects> git clone -b minimalistic https://github.com/AlexAtNet/WPFFSharpQuickStart
PS C:\Projects> cd WPFFSharpQuickStart
PS C:\...\WPFFSharpQuickStart> _

The content of App.config, solution, project and assembly info files is typical and can be ignored for now. More important bits and pieces are in App.xaml, Program.fs, MainViewModel.fs, MainWindow.xaml and Services.fs.

Program.fs

This is starting point of the application. It reads App.xaml and starts the app.

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

[<STAThread>]
[<EntryPoint>]
let main(_) =
  let appUri = Uri ("App.xaml", UriKind.Relative)
  let application = appUri
                    |> Application.LoadComponent
                    :?> Application
  application.Run() |> ignore
  0

App.xaml

Minimalistic App.xaml.

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:MyApp"
             StartupUri="MainWindow.xaml" />

MainWindow.xaml

The main form of the application. Specifies which class is used as DataContext, displays welcome message.

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyApp;assembly=MyApp"
        Title="My Application"
        Height="350"
        Width="525">
    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>
    <Grid>
        <Border BorderBrush="{x:Null}"
                Height="50">
            <TextBlock Text="{Binding WelcomeText}"
                       VerticalAlignment="Stretch"
                       TextAlignment="Center"
                       FontFamily="Segoe"
                       FontSize="26" />
        </Border>
    </Grid>
</Window>

MainViewModel.fs

View model of the MainWindow.xaml. Provides it with the welcome text.

namespace MyApp

open MyApp.Library

type MainViewModel () =
  let welcomeTextProvider = WelcomeTextProvider ()

  member vm.WelcomeText
    with get() = welcomeTextProvider.GetWelcomeText ()

Service.fs

namespace MyApp.Library

type WelcomeTextProvider () =
    member x.GetWelcomeText() =
        "Hi there. I'm a new awesome app!"

The project can be build with the following MSBuild command:

PS c:\...> msbuild WPFFSharpQuickStart.sln /p:VisualStudioVersion=14.0

If it fails with The term 'msbuild' is not recognized ... (in PowerShell), then the path c:\Windows\Microsoft.NET\Framework64\v4.0.30319 is not added to your environment variable PATH. Set it as follows and try to build the project again.

PS c:\...> $env:Path += ";c:\Windows\Microsoft.NET\Framework64\v4.0.30319"

If everything goes ok, the following should be printed at the end of the pretty large output:

Build succeeded.
    0 Warning(s)
    0 Error(s)

The command to run the app:

PS c:\...> .\MyApp\bin\Debug\MyApp.exe

All these commands can be executed from the integrated VS Code terminal.

Build and run. Everything works:

Remember that F# files in the fsproj should go in the order of compilation and that the last one should be Program.fs. Add new fs files to fsproj file as "Compile" nodes. When adding new XAML files, add them as Resources.