Quickstart WPF F#-only app in VSCode - Part 2

The first part shown how to create a WPF F# project with simple window and its view model, build this project and run it.

Now lets add FsXaml using packet, use it to create types from XAML and create user control. All by directly modifying project files and run commands from the VS Code terminal.

paket is a nice alternative to nuget. Its executable can be downloaded from the paket's project repository on GitHub (see this link. paket.exe should be placed into the project's folder or in one of the folders listed in the PATH environment variable in order to be accessible from the terminal.

Make the initial paket files, including empty paket.dependencies:

PS C:\...\WPFFSharpQuickStart> ./paket init

Install FsXaml for WPF and add reference:

PS C:\...\WPFFSharpQuickStart> ./paket add FsXaml.Wpf --version 3.1.6 --project MyApp\MyApp.fsproj

The FsXaml wants FSharp.Core 4.3 but the project references FSharp.Core 4.4 so the MSBuild complains a bit about it. It can be fixed by adding the following mapping to the App.config's configuration node:

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
          <assemblyIdentity name="FSharp.Core"
                            publicKeyToken="b03f5f7f11d50a3a"
                            culture="neutral"/>
          <bindingRedirect oldVersion="4.3.0.0"
                           newVersion="4.4.0.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

After FsXaml is installed, loading and instantiating XAML components and user controls become much simpler. For example, the Program.fs becomes

open System
open FsXaml

type App = XAML<"App.xaml">

[<STAThread>]
[<EntryPoint>]
let main (_) =
  let application = App()
  application.Run () |> ignore
  0

Although it works perfectly now, it is better to define XAML-based types in the special Controls.fs file in the application's namespace:

Controls.fs

namespace MyApp

open FsXaml

type App = XAML<"App.xaml">

Include it to the project:

MyApp.fsproj

    <Compile Include="MainViewModel.fs" />
+   <Compile Include="Controls.fs" />
    <Compile Include="Program.fs" />

and modify the entry point file:

Program.fs

open System
open MyApp

[<STAThread>]
[<EntryPoint>]
let main (_) =
  let application = App()
  application.Run () |> ignore
  0

FsXaml greatly simplifies creating of user controls:

Welcome.xaml

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Border BorderBrush="{x:Null}"
            Height="50">
        <TextBlock Text="{Binding WelcomeText}"
                   VerticalAlignment="Stretch"
                   TextAlignment="Center"
                   FontFamily="Segoe"
                   FontSize="26" />
    </Border>
</UserControl>

WelcomeViewModel.fs

namespace MyApp

open MyApp.Library

type WelcomeViewModel () =
  let welcomeTextProvider = WelcomeTextProvider ()

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

MyApp.fsproj

...
    <Compile Include="AssemblyInfo.fs" />
+   <Resource Include="Welcome.xaml" />
+   <Compile Include="WelcomeViewModel.fs" />
    <Resource Include="MainWindow.xaml" />
...

Controls.fs

...
type App = XAML<"App.xaml">
type Welcome = XAML<"Welcome.xaml">

MainWindow.xaml

...
    </Window.DataContext>
    <Grid>
        <local:Welcome DataContext="{Binding Welcome}">
    </Grid>
...

And that's it. Now build and run, everything should work.

You can get the version of the WPFFSharpQuickStart project with paket and FsXaml by getting the fsxaml branch:

C:\...> git clone -b fsxaml https://github.com/AlexAtNet/WPFFSharpQuickStart