About a year ago XAML type provider (that now a part of fsharpx project) was born. First of all, happy birthday XAML type provider and thank you everyone who was involved.
Up to XAML type provider release the best option for F# WPF development was to split app into two parts: C# project with all XAML stuff for best tooling support and F# project with all source code. Daniel Mohl have created a project template “F# and C# Win App (WPF, MVVM)” that illustrates this approach end to end (read more about this in his blog).
XAML type provider is an amazing thing that makes available full-featured WPF development completely in F#. Steffen Forkmann has an excellent blog post about its usage “WPF Designer for F#“. It is probably one of my favorite posts about F# at all, it shows a real beauty and excellence of the technology. This approach was already templated by Daniel Mohl – “F# Empty Windows App (WPF)“.
I think that a natural desire is to have an F# MVVM app using XAML type provider. It can be done by combining these two templates. At the first step, create a new project from “F# Empty Windows App (WPF)” template, and leave App.fs file without any changes.
module MainApp open System open System.Windows open System.Windows.Controls open FSharpx type MainWindow = XAML<"MainWindow.xaml"> let loadWindow() = let window = MainWindow() window.Root [<STAThread>] (new Application()).Run(loadWindow()) |> ignore
Now we need to define a ViewModel for MainWindow. I have reused BaseViewModel and RelayCommand from polyglot approach template.
namespace ViewModels 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) |]) type RelayCommand (canExecute:(obj -> bool), action:(obj -> unit)) = let event = new DelegateEvent<EventHandler>() interface ICommand with [<CLIEvent>] member x.CanExecuteChanged = event.Publish member x.CanExecute arg = canExecute(arg) member x.Execute arg = action(arg) type MainViewModel () = inherit ViewModelBase() let mutable name = "Noname" member x.Name with get () = name and set value = name <- value x.OnPropertyChanged "Name" member x.OkCommand = new RelayCommand ((fun canExecute -> true), (fun action -> MessageBox.Show(sprintf "Hello, %s" x.Name) |> ignore))
The last and probably most tricky part is a XAML. Pay attention to the row number four (local namespace definition). You need to specify assembly part even if your view model located in the same assembly as XAML. It happens because type provider works in another one.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ViewModels;assembly=FsharpMVVMWindowsApp" Title="MVVM and XAML Type provider" Height="120" Width="300"> <Window.DataContext> <local:MainViewModel></local:MainViewModel> </Window.DataContext> <Grid > <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Label FontSize="16">What is your name?</Label> <TextBox Grid.Row="1" FontSize="16" Text="{Binding Name, Mode=TwoWay}"/> <Button Grid.Row="2" FontSize="16" Command="{Binding OkCommand}">Ok</Button> </Grid> </Window>
Voila, it works now.
Thanks for this great article. I had the basic example working as shown above but then I separated the ViewModelBase and the MainViewModel classes into separate F# files. The project compiles but I get the warning: “warning FS0988: Main module of program is empty: nothing will happen when it is run”.
Then when I run the app nothing happens.
Any ideas?
At the top of the the ViewModelBase.fs file I have defined the namespace ViewModels.
In the MainViewModel.fs file I have also defined the namespace ViewModels.
The compilation warning occurs in the MainViewModel.fs file.
Thanks
Ah, never mind. Moving the App.fs down to the bottom of the list of files solves the issue.
It would be epic if you could please comment the type definitions line by line. I’m coming from a WinForms background and am new to WPF. It feels like I just hit my face into a brick wall !
I can recommend you to start from MVVM Light docs (https://mvvmlight.codeplex.com/) especially from “Understanding the MVVM Pattern” video – http://channel9.msdn.com/blogs/kreekman/techdays-2010-understanding-the-model-view-viewmodel-pattern
Both links for the Xaml type provider are now dead
I think that everything is in FsXaml right now https://github.com/fsprojects/FsXaml