I have the very latest version of Visual Studio 2017 installed. I selected F# language support and F# desktop support. After restarting and going to File -> New Project I was ex
You can create both WPF and WinForms applications in F#. There is no template for it, but it is certainly possible and many people do this. To create a simple WinForms application, you can do the following:
Create a new console application. Go to project properties and change "Output type" in the "Application" page from "Console application" to "Windows Application"
Right click on "References" in the project and add reference to "System.Windows.Forms" and "System.Drawing" (in the "Framework" tab).
Replace the code in Program.fs
with the following:
open System.Windows.Forms
let f = new Form()
f.Controls.Add(new Label(Text="Hello world!"))
Application.Run(f)
For anything bigger, you will probably want to use a nice F# GUI library such as the FsXaml project mentioned by Isaac or Gjallarhorn, but the basic first steps will be the same - create a console project, make it a windows project and then add relevant references to GUI frameworks.
And coming "soon" to an IDE near you:
“You can expect two releases from us in 2019, .NET Core 3 and .NET Framework 4.8.”
https://blogs.msdn.microsoft.com/dotnet/2018/05/07/net-core-3-and-support-for-windows-desktop-applications/
As far as I know, there are no "out of the box" templates for WPF or WinForms on F# but (at least in VS2015) there were a set of community templates for WPF apps. To be honest, you don't need a template really, especially if you use the FSXaml project which makes it pretty easy to do it by hand (https://github.com/fsprojects/FsXaml).
This isn't an easy answer. There is no built-in project template for those projects because neither the Windows Forms nor the WPF designer understand F#. We just got the ASP.NET Core templates for F# so we shouldn't complain... much.
On the other hand, a Winforms or WPF application is just C# code. Anything you do in the designer ends up as code in the form file. A Winforms or WPF application are "just" Console applications that set up the proper environment and create the forms and controls.
This is actually easier using XAML and WP, especially if you use MVVM or a similar architecture. That's because you can develop the XAML markup separately from the F# code and bind your data to XAML. You can even create a WPF Class library project, create Windows, pages and controls there without any code and then use them in your F# project.
There are a few libraries that make this easier. One option is Elmish.WPF. You can create the XAML pages and windows in a separate project and then create models etc in F#, bind them together and start the main form. If you check the repo's example most of the code defines records and commands as F# functions, eg :
type ClockMsg =
| Tick of DateTime
type ClockModel =
{ Time: DateTime }
type Msg =
| ClockMsg of ClockMsg
| Increment
| Decrement
| SetStepSize of int
type Model =
{ Count: int
StepSize: int
Clock: ClockModel }
and
let init() = { Count = 0; StepSize = 1; Clock = { Time = DateTime.Now }}
let clockUpdate (msg:ClockMsg) (model:ClockModel) =
match msg with
| Tick t -> { model with Time = t }
let update (msg:Msg) (model:Model) =
match msg with
| Increment -> { model with Count = model.Count + model.StepSize }
| Decrement -> { model with Count = model.Count - model.StepSize }
| SetStepSize n -> { model with StepSize = n }
| ClockMsg m -> { model with Clock = clockUpdate m model.Clock }
Binding them together is relatively simple :
let view _ _ =
let clockViewBinding : ViewBindings<ClockModel,ClockMsg> =
[ "Time" |> Binding.oneWay (fun m -> m.Time) ]
[ "Increment" |> Binding.cmd (fun m -> Increment)
"Decrement" |> Binding.cmdIf (fun m -> Decrement) (fun m -> m.StepSize = 1)
"Count" |> Binding.oneWay (fun m -> m.Count)
"StepSize" |> Binding.twoWay (fun m -> (double m.StepSize)) (fun v m -> v |> int |> SetStepSize)
"Clock" |> Binding.vm (fun m -> m.Clock) clockViewBinding ClockMsg ]
And running the entire application
[<EntryPoint;STAThread>]
let main argv =
Program.mkSimple init update view
|> Program.withSubscription subscribe
|> Program.runWindow (Elmish.CounterViews.MainWindow())
The code above comes from the Counter sample. The XAML views are defined in the CounterViews project. You can even delete the .cs
files and the project will compile just fine.